Пример #1
0
 def func_browse_eve(self):
     folder = QDir.toNativeSeparators(
         QFileDialog.getExistingDirectory(None, "Eve Directory", "", QFileDialog.ShowDirsOnly))
     if not folder.endswith(os.sep):
         folder += os.sep
     self.ui.txt_client_path.setText(folder)
     self.settings['eve_path'] = folder
Пример #2
0
    def generateAndExportClicked(self):

        g = Generator()
        g.tileWidth = self.tileWidthSpinBox.value()
        g.tileHeight = self.tileHeightSpinBox.value()
        g.forcePot = self.forcePotCheckBox.isChecked()
        g.isTransparent = self.transparentCheckbox.isChecked()
        g.bgColor = self.backgroundColorEdit.getColor()
        g.reorder = self.reorderTilesCheckBox.isChecked()
        g.padding = self.paddingSpinBox.value()

        target = g.create(self.pixmapWidget.pixmap);

        # export
        self.lastDir = os.path.dirname(self.path)
        targetPath = QFileDialog.getSaveFileName(self, 'Export', self.lastDir, 'PNG (*.png)')
        if targetPath:
            target.save(targetPath[0])
            showPixmap = QPixmap.fromImage(target)
            if self.showPixmapWidget:
                self.showPixmapWidget.deleteLater()
                del self.showPixmapWidget
            self.showPixmapWidget = PixmapWidget()
            self.showPixmapWidget.setWindowIcon(self.windowIcon())
            self.showPixmapWidget.setWindowTitle(os.path.basename(targetPath[0]))
            self.showPixmapWidget.resize(showPixmap.width(), showPixmap.height())
            self.showPixmapWidget.setPixmap(showPixmap)
            self.showPixmapWidget.show()
Пример #3
0
 def onSaveLog(self):
     fileName = QFileDialog.getSaveFileName(self, "Save as", os.getcwd(),
         "Log files (*.log);;Text files (*.txt);;All files (*.*)")[0]
     if fileName:
         import codecs
         f = codecs.open(fileName, 'w', 'utf-8')
         f.write(self.txtEdtOutput.toPlainText())
         f.close()
Пример #4
0
 def openFileNameDialog(self):
     options = QFileDialog.Options()
     options |= QFileDialog.DontUseNativeDialog
     self.fileName, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","All Files (*);;Python Files (*.py)", options=options)
     if self.fileName:
         self.path = os.path.dirname(self.fileName)
         self.imageFiles = []
         self.random_index = []
         self.max_index = []
         self.imageFiles, self.random_index, self.path, self.max_index = self.getImageNames2() 
         self.slideIndex = self.imageFiles.index(self.fileName) -1
Пример #5
0
 def open(self):
     fileDialog = QFileDialog(self)
     supportedMimeTypes = QMediaPlayer.supportedMimeTypes()
     if not supportedMimeTypes:
         supportedMimeTypes.append("video/x-msvideo") # AVI
     fileDialog.setMimeTypeFilters(supportedMimeTypes)
     moviesLocation = QStandardPaths.writableLocation(QStandardPaths.MoviesLocation)
     fileDialog.setDirectory(moviesLocation)
     if fileDialog.exec_() == QDialog.Accepted:
         self.playlist.addMedia(fileDialog.selectedUrls()[0])
         self.player.play()
Пример #6
0
 def bj(self):
     it=self.ui.tableWidget.item(self.ui.tableWidget.currentRow(),0)#self.ui.tableWidget.currentColumn()))
     if it==None:
         return        
     contactid=int(it.text())
     (fileName,fileType)= QFileDialog.getOpenFileName(None,"Open Excel file", r"C:\Users\group2\Desktop\备料计划导出文件","Excel Files ( *.xlsx *.xls)")
     items_chuku=readBeiliaofile(fileName)
     r=backend.getContactItems(contactid)
     print(r,items_chuku)
     (left,notequal,right)=bjitems(r,items_chuku)
     c=chuku.ContactDlg(self)
     c.showdata(left,notequal,right)
     c.showMaximized()
     c.exec()
Пример #7
0
    def open(self):
        fileName, _ = QFileDialog.getOpenFileName(self)
        if fileName:
            existing = self.findMdiChild(fileName)
            if existing:
                self.mdiArea.setActiveSubWindow(existing)
                return

            child = self.createMdiChild()
            if child.loadFile(fileName):
                self.statusBar().showMessage("File loaded", 2000)
                child.show()
            else:
                child.close()
Пример #8
0
 def chooserootdir(self):
     currentdir = self.settings['RootFolder']
     flags = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
     newroot = QFileDialog.getExistingDirectory(None,
                                                "Open Directory",
                                                currentdir, flags)
     if newroot != "" and str(newroot) != currentdir:
         self.settings['RootFolder'] = str(newroot)
         filesettings.settingsToFile(self.settings, self.settings_path)
         self._window.rootfolder.setText(newroot)
         # we delete the already present downloadthread and recreate it
         # because otherwise it uses the old download folder. I don't know
         # if there's a cleaner approach
         del self.downloadthread
         self.downloadthread = DownloadThread(self.user,
                                              self.settings['RootFolder'],
                                              self)
         self.downloadthread.dumpuser.sig.connect(self.dumpUser)
         self.dumpUser()
Пример #9
0
 def loadC3DFile(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.scene.object_builder.create_object_from_file(
         "c3d", str(filename))
Пример #10
0
 def loadHeightMap(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.loadHeightMap(str(filename))
Пример #11
0
 def loadMorphableGraphStateMachine(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.scene.object_builder.create_object_from_file(
         "mg.zip", str(filename))
Пример #12
0
 def loadASFFile(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     if filename is not None:
         self.sceneManager.scene.object_builder.create_object_from_file(
             "asf", str(filename))
Пример #13
0
 def open_file(self, _):
     file_name = QFileDialog.getOpenFileName(self)
     if not file_name[0]:
         return
     self.loadcov(file_name[0])
Пример #14
0
 def add_category(self):
     files = QFileDialog.getOpenFileNames(
         self.window, "Dodaj kategorię",
         os.getcwd() + "/User_Files/Categories_to_add", "Plik PDF (*.pdf)")
     self.to_add = files[0]
     self.window.ui.CategoriesToAdd.setText(str(files[0]))
Пример #15
0
 def openFileNameDialog(self):
     fileName, _ = QFileDialog.getOpenFileName(self,"Load Bafang Settings", "","Text Files (*.json)")
     return fileName
 def Event_ImagePath(self):
     self.window.Line_Image.setText(QFileDialog.getOpenFileName()[0])
Пример #17
0
 def _action_select_dir(self):
     dir_path = QFileDialog.getExistingDirectory(self, "Select a directory")
     if dir_path:
         self.setItem(self.currentRow(), 1, QTableWidgetItem(dir_path))
Пример #18
0
 def save_now_image(self):
     if(self.img.is_load_image == True):
         imagepath = QFileDialog.getSaveFileName(
             None, '保存图片', './', "Images (*.jpg)")
         if(imagepath[0] != ''):
             self.img.save_image(self.img.nowImage, imagepath[0])
Пример #19
0
 def on_open_img(self):
     imagepath = QFileDialog.getOpenFileName(
         None, '打开图片', self.filepath, "Images (*.jpg *.png *.bmp)")
     self.__init_img(imagepath[0])
Пример #20
0
 def guardar(self):
     file = QFileDialog.getSaveFileName(self, 'Guardar Archivo...', '.',
                                        'JSON (*.json)')
     print(file)
     self.paqueteria.guardar(file[0])
Пример #21
0
 def abrir(self):
     file = QFileDialog.getOpenFileName(self, 'Abrir archivo', '.',
                                        'JSON(*.json)')
     self.paqueteria.recuperar(file[0])
Пример #22
0
 def loadCustomUnityFormat(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.scene.object_builder.create_object_from_file(
         "_m.json", str(filename))
Пример #23
0
 def saveFile(self):
     filename, _ = QFileDialog.getSaveFileName(self)
     if filename:
         self.addressWidget.writeToFile(filename)
Пример #24
0
 def selectProjectPath(self):
     dialog = QFileDialog(self)
     dialog.setFileMode(QFileDialog.AnyFile)
     dialog.setOption(dialog.ShowDirsOnly, True)
     dialog.selectFile(self.ui.lineEdit_2.text())
     dialog.setWindowTitle('Name A New Directory For Project')
     if dialog.exec_():
         self.ui.lineEdit.setText(dialog.selectedFiles()[0])
Пример #25
0
 def saveFileDialog(self):
     fileName, _ = QFileDialog.getSaveFileName(self,"Backup Bafang settings","","Text Files (*.json)")
     return fileName
Пример #26
0
    def open_img(self):
        fname = QFileDialog.getOpenFileName(self)
        print(fname[0])

        self.cv2Label.set_img(fname[0])
Пример #27
0
def open_image():
    name = QFileDialog.getOpenFileName(w, 'Open File')
    print(name)
    w.image = QtGui.QImage(name[0])
    pixmap = QtGui.QPixmap(w.image)
    w.imageLabel.setPixmap(pixmap)
Пример #28
0
 def load_file(self):
     file_name = QFileDialog.getOpenFileName(self)
     #tr('Open AHLTA template'), '', tr('AHLTA template (*.txt)'))
     return file_name
Пример #29
0
class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.load_ui()
        self.figlabels()
        self.imgs = []
        self.subj = []
        # self.figlabels = cv2.imread('figlabels.png')
        self.make_connect()
        self.inputExists = False
        self.defaultDirectoryExists = False
        self.annotationExists: False
        self.isSegmented = False
        self.files = None
        self.temperaturesWereAcquired = False

    def load_ui(self):
        loader = QUiLoader()
        path = os.fspath(Path(__file__).resolve().parent / "form.ui")
        ui_file = QFile(path)
        ui_file.open(QFile.ReadOnly)
        self.ui_window = loader.load(ui_file, self)
        ui_file.close()

    def make_connect(self):
        QObject.connect(self.ui_window.actionCargar_imagen,
                        SIGNAL('triggered()'), self.openImage)
        QObject.connect(self.ui_window.actionCargar_carpeta,
                        SIGNAL('triggered()'), self.openFolder)
        QObject.connect(self.ui_window.segButton, SIGNAL('clicked()'),
                        self.segment)
        QObject.connect(self.ui_window.tempButton, SIGNAL('clicked()'),
                        self.temp_extract)
        QObject.connect(self.ui_window.manualSegButton, SIGNAL('clicked()'),
                        self.manual_segment)
        QObject.connect(self.ui_window.refreshTimePlot, SIGNAL('clicked()'),
                        self.makeTimePlot)
        QObject.connect(self.ui_window.nextImageButton, SIGNAL('clicked()'),
                        self.nextImage)
        QObject.connect(self.ui_window.previousImageButton,
                        SIGNAL('clicked()'), self.previousImage)
        QObject.connect(self.ui_window.saveButton, SIGNAL('clicked()'),
                        self.saveImage)
        QObject.connect(self.ui_window.fullPlotButton, SIGNAL('clicked()'),
                        self.fullPlot)
        QObject.connect(self.ui_window.reportButton, SIGNAL('clicked()'),
                        self.exportReport)

    def messagePrint(self, message):
        #INPUT: string to print
        #OUTPUT: none
        #ACTION: generate out.html file and refresh it in Messages QTextArea
        log_path = "outputs/logs.html"
        out_file = open(log_path, "w")
        out_file.write(message)
        out_file.close()
        self.ui_window.textBrowser.setSource(log_path)
        self.ui_window.textBrowser.reload()

    def findImages(self):
        self.fileList = []
        for root, dirs, files in os.walk(self.defaultDirectory):
            for file in files:
                if (file.endswith(".jpg")):
                    self.fileList.append(os.path.join(root, file))
        self.imageQuantity = len(self.fileList)
        self.imageIndex = 0
        self.files = files
        self.sortFiles()
        self.outfiles = []
        for i in range(len(files)):
            self.outfiles.append("outputs/" +
                                 files[i])  #Creating future output file names
        self.ui_window.inputLabel.setText(self.files[self.imageIndex])

    def sortFiles(self):
        """Sort file list to an alphanumeric reasonable sense"""
        convert = lambda text: int(text) if text.isdigit() else text
        alphanum_key = lambda key: [
            convert(c) for c in re.split('([0-9]+)', key)
        ]
        self.fileList = sorted(self.fileList, key=alphanum_key)
        self.files = sorted(self.files, key=alphanum_key)

    def getTimes(self):
        """
        Converts standarized names of file list into a list of 
        integers with time capture in minutes
        """
        if (type(self.fileList) == str):
            self.timeList = int(self.fileList).rsplit(".")[0][1:]
        elif type(self.fileList) == list:
            out_list = []
            for i in range(len(self.fileList)):
                out_list.append(int(self.files[i].rsplit(".")[0][1:]))
            self.timeList = out_list
        else:
            return None

    def nextImage(self):
        if self.imageIndex < len(self.fileList) - 1:
            self.imageIndex += 1
            self.ui_window.inputImg.setPixmap(self.fileList[self.imageIndex])
            self.opdir = self.fileList[self.imageIndex]
            self.ui_window.inputLabel.setText(self.files[self.imageIndex])

            if self.sessionIsSegmented:
                #Sentences to display next output image if session was already
                #segmented
                self.showOutputImageFromSession()
                if self.temperaturesWereAcquired:
                    self.messagePrint(
                        "La temperatura media es: " +
                        str(self.meanTemperatures[self.imageIndex]))
                    self.ui_window.temperatureLabel.setText(
                        str(np.round(self.meanTemperatures[self.imageIndex],
                                     3)))

    def previousImage(self):
        if self.imageIndex >= 1:
            self.imageIndex -= 1
            self.ui_window.inputImg.setPixmap(self.fileList[self.imageIndex])
            self.opdir = self.fileList[self.imageIndex]
            self.ui_window.inputLabel.setText(self.files[self.imageIndex])

            if self.sessionIsSegmented:
                #Sentences to display next output image if session was already
                #segmented
                self.showOutputImageFromSession()
                if self.temperaturesWereAcquired:
                    self.messagePrint(
                        "La temperatura media es: " +
                        str(self.meanTemperatures[self.imageIndex]))
                    self.ui_window.temperatureLabel.setText(
                        str(np.round(self.meanTemperatures[self.imageIndex],
                                     3)))

    def saveImage(self):
        #Saves segmented image
        pass

    def feetSegment(self):
        self.messagePrint("Segmentando imagen")
        self.i2s = ImageToSegment()
        self.i2s.setPath(self.opdir)
        self.i2s.extract()
        self.showSegmentedImage()
        self.isSegmented = True
        self.messagePrint("Imagen segmentada exitosamente")

    def sessionSegment(self):
        self.messagePrint("Segmentando toda la sesion...")
        self.s2s = SessionToSegment()
        self.s2s.setPath(self.defaultDirectory)
        self.s2s.whole_extract(self.fileList)
        self.produceSegmentedSessionOutput()
        self.showOutputImageFromSession()
        self.messagePrint("Se ha segmentado exitosamente la sesion")
        self.sessionIsSegmented = True

    def showSegmentedImage(self):
        #Applies segmented zone to input image, showing only feet
        threshold = 0.5
        img = plt.imread(self.opdir) / 255
        Y = self.i2s.Y_pred
        Y = Y / Y.max()
        Y = np.where(Y >= threshold, 1, 0)
        self.Y = remove_small_objects(
            Y[0])  #Eventually required by temp_extract
        Y = cv2.resize(
            Y[0], (img.shape[1], img.shape[0]),
            interpolation=cv2.INTER_NEAREST
        )  # Resize the prediction to have the same dimensions as the input
        plt.imsave("outputs/output.jpg", Y * img[:, :, 0], cmap='gray')
        self.ui_window.outputImg.setPixmap("outputs/output.jpg")

    def produceSegmentedSessionOutput(self):
        #Recursively applies showSegmentedImage to whole session
        self.Y = []
        for i in range(len(self.outfiles)):
            threshold = 0.5
            img = plt.imread(self.fileList[i]) / 255
            Y = self.s2s.Y_pred[i]
            Y = Y / Y.max()
            Y = np.where(Y >= threshold, 1, 0)
            self.Y.append(
                remove_small_objects(Y))  #Eventually required by temp_extract
            Y = cv2.resize(
                Y, (img.shape[1], img.shape[0]),
                interpolation=cv2.INTER_NEAREST
            )  # Resize the prediction to have the same dimensions as the input
            plt.imsave(self.outfiles[i], Y * img[:, :, 0], cmap='gray')

    def showOutputImageFromSession(self):
        self.ui_window.outputImg.setPixmap(self.outfiles[self.imageIndex])

    def segment(self):
        if self.ui_window.sessionCheckBox.isChecked():

            if self.defaultDirectoryExists:
                self.sessionSegment()
                print("Entering session segment")
            else:
                self.messagePrint("No se ha seleccionado sesion de entrada")
        else:
            if self.inputExists:
                self.feetSegment()
                print("Entering image segment")
            else:
                self.messagePrint("No se ha seleccionado sesion de entrada")

    def manual_segment(self):
        print("Se abrirá diálogo de extracción manual")
        self.manual = manualSeg()
        self.manual.show()
        return

    def temp_extract(self):
        if (self.inputExists
                and (self.isSegmented or self.sessionIsSegmented)):
            if self.ui_window.sessionCheckBox.isChecked(
            ):  #If segmentation was for full session
                self.meanTemperatures = [
                ]  #Whole feet mean temperature for all images in session
                for i in range(len(self.outfiles)):
                    self.meanTemperatures.append(
                        mean_temperature(self.s2s.Xarray[i, :, :, 0],
                                         self.Y[i][:, :, 0],
                                         plot=False))
                self.messagePrint("La temperatura media es: " +
                                  str(self.meanTemperatures[self.imageIndex]))
                self.temperaturesWereAcquired = True
            else:  #If segmentation was for single image
                mean = mean_temperature(self.i2s.Xarray[:, :, 0],
                                        self.Y[:, :, 0],
                                        plot=False)
                self.messagePrint("La temperatura media es: " + str(mean))

            if (self.ui_window.plotCheckBox.isChecked()
                ):  #If user asked for plot
                self.messagePrint("Se generara plot de temperatura...")
                self.getTimes()
                print(self.timeList)
                self.tempPlot()

        elif self.inputExists:
            self.messagePrint("No se ha segmentado previamente la imagen ")
        else:
            self.messagePrint("No se han seleccionado imagenes de entrada")

    def tempPlot(self):
        plt.figure()
        plt.plot(self.timeList, self.meanTemperatures, '-o')
        plt.title("Temperatura media de pies")
        plt.xlabel("Tiempo (s)")
        plt.ylabel("Temperatura (°C)")
        plt.grid()
        plt.show()
        #Produce plot

    def figlabels(self):
        #  Get info from directory path name and obtain time indexes based on name
        pass

    def openImage(self):
        self.fileDialog = QFileDialog(self)
        if self.defaultDirectoryExists:
            self.fileDialog.setDirectory(self.defaultDirectory)
        else:
            self.fileDialog.setDirectory(QDir.currentPath())
        filters = ["*.png", "*.xpm", "*.jpg"]
        self.fileDialog.setNameFilters("Images (*.png *.jpg)")
        self.fileDialog.selectNameFilter("Images (*.png *.jpg)")
        #self.fileDialog.setFilter(self.fileDialog.selectedNameFilter())
        self.opdir = self.fileDialog.getOpenFileName()[0]
        self.imagesDir = os.path.dirname(self.opdir)
        if self.opdir:
            self.inputExists = True
            self.ui_window.inputImg.setPixmap(self.opdir)

    def openFolder(self):
        self.folderDialog = QFileDialog(self)
        self.folderDialog.setDirectory(QDir.currentPath())
        self.folderDialog.setFileMode(QFileDialog.FileMode.Directory)
        self.defaultDirectory = self.folderDialog.getExistingDirectory()
        self.imagesDir = self.defaultDirectory
        if self.defaultDirectory:
            self.defaultDirectoryExists = True
            first_image = str(self.defaultDirectory + "/t0.jpg")
            print(first_image)
            self.ui_window.inputImg.setPixmap(first_image)
            self.opdir = first_image
            self.inputExists = True
            self.findImages()

    def makeTimePlot(self):
        if self.inputExists:
            x = np.array([0, 1, 5, 10, 15, 20])
            y = np.array([35.5, 35.7, 36, 37.2, 37.3, 37.5])
            fig = plt.figure(figsize=(9.6, 4))
            plt.plot(x, y, label='Paciente 1')
            plt.legend()
            plt.grid()
            plt.xlabel("Tiempo [minutos]")
            plt.ylabel("Temperatura [°C]")
            plt.title("Time plot")
            #plt.show()
            plt.savefig('/ouputs/fresh.png')
            self.ui_window.timePlot.setPixmap('/outputs/outputs//fresh.png')
            self.messagePrint("Se ha actualizado el TimePlot")
        else:
            self.messagePrint(
                "No se puede actualizar el TimePlot. No se ha seleccionado una imagen de entrada"
            )

    def fullPlot(self):
        self.messagePrint("Preparando full plot...")
        #show_temperatures("paciente" , fn="mean" , range_ = [22.5 , 33.5])
        self.messagePrint("Full plot generado exitosamente")
        pass

    def exportReport(self):
        self.messagePrint("Generando reporte...")
        #GENERATE A PDF REPORT FOR THE PATIENT
        #INPUT: SELF, PATIENT DIR
        #RETURN: NONE
        #ACTION: COMPILE PDF TEXT BASED ON
        self.messagePrint("Reporte generado exitosamente")
        pass

    def animate(self):
        """
        Produces gif animation based on mean temperatures for whole session
        Initially, all feet has same color, for section segmentation has been not implemented yet
        """
        self.messagePrint("Iniciando animacion...")
        pass
Пример #30
0
 def pick_location(self):
     dialog = QFileDialog()
     folder_path = dialog.getExistingDirectory(self, "Select Folder")
     self.location_input.setText(folder_path)
     return folder_path
Пример #31
0
 def loadMorphableModelFile(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.scene.object_builder.create_object_from_file(
         "mm.json", str(filename))
 def loadFromDialog(self):
     # TODO(jacob): Make this menu remember the last file opened
     filepaths, _ = QFileDialog.getOpenFileNames(self.parent(),
                                                 'Load PDL files')
     if len(filepaths) > 0:
         self.load_from_files(filepaths)
Пример #33
0
 def loadBlendController(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.loadBlendController(str(filename))
Пример #34
0
    def saveButton(self):
        try:
            saveFilePath = QFileDialog.getExistingDirectory(self.ui, "选择存储路径")
            number = self.ui.spinBox.value() #获取数字,int类型
            text = self.ui.KeyLineEdit.text()#读取关键词文本框内容
            #读取Excel数据
            book = xlrd.open_workbook(self.filePath)
            sheet = book.sheet_by_index(0)

            sheet_col = sheet.col_values(colx=number)
            sheet_row = sheet.row_values(rowx=0)#表头
            #检索有指定有该关键词的行
            liRowAccess = []#记录检索通过的数据的行数索引
            i = 0
            for row, content in enumerate(sheet_col): #真实row要加1]
                if row>0 and type(content) is str and (text in content):
                    liRowAccess.append(row)
                else:
                    continue
                i+=1

            #过滤后的每行存入二维数组中,【行坐标,0开始,到最后一个数据结束】【列坐标,0开始到最后一个标题结束】
            filter = [[' ' for i in range(len(sheet_row))] for i in range(len(liRowAccess))]#二维数组初始化
            for r in range(len(liRowAccess)):
                for c in range(len(sheet_row)):
                    filter[r][c] = sheet.row_values(rowx=liRowAccess[r])[c]

            #新建excel
            # 创建一个Excel workbook 对象
            book = openpyxl.Workbook()
            # 创建时,会自动产生一个sheet,通过active获取
            sh = book.active
            formName = self.ui.KeyLineEdit_2.text()#获取表名
            fileName = self.ui.FileLineEdit.text() # 获取文件名
            sh.title = formName

            #写入标题栏
            for i in range(len(sheet_row)):
                sh.cell(1, i+1).value = sheet_row[i]#openpyxl库中行号列号从1开始
                sh.cell(1, i+1).font = Font(
                        size=12,    # 设定文字大小
                        bold=True,  # 设定为粗体
                        )


            #写入数据
            for r in range(len(liRowAccess)):
                for c in range(len(sheet_row)):
                    sh.cell(r+2,c+1).value = filter[r][c]

            book.save(saveFilePath+'/'+fileName+'.xlsx')
            #导出成功提示
            QMessageBox.information(
                self.ui,
                '导出成功',
                '导出Excel成功,请到您指定的路径下查看')
        except:
            #给个弹出框显示无导入文件,请先导入文件。
            QMessageBox.critical(
                self.ui,
                '错误',
                '导入文件错误!')
Пример #35
0
 def loadConstraintsFormat(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.loadConstraintsFormat(str(filename))
Пример #36
0
 def openCSV(self):
     fileName = QFileDialog.getOpenFileName(self, "Select a file",
         os.getcwd(), "CSV Files (*.csv)")[0]
     if fileName:
         self.loadCSV(fileName, notifyExcept = True)
Пример #37
0
 def runPythonScript(self):
     filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
     self.sceneManager.runPythonScript(str(filename))
Пример #38
0
    def saveAs(self):
        fileName, _ = QFileDialog.getSaveFileName(self, "Save As", self.curFile)
        if not fileName:
            return False

        return self.saveFile(fileName)
Пример #39
0
 def select_dir(self):
     dir_path = QFileDialog.getExistingDirectory(self, 'Select Directory', os.path.expanduser(self.root_save_dir) )
     if dir_path:
         self.root_save_dir = dir_path
         self.save_dir_label.setText("Save Dir : {}".format(self.root_save_dir))
Пример #40
0
 def openFile(self):
     filename, _ = QFileDialog.getOpenFileName(self)
     if filename:
         self.addressWidget.readFromFile(filename)
Пример #41
0
class FittingResultViewer(QDialog):
    PAGE_ROWS = 20
    logger = logging.getLogger("root.QGrain.ui.FittingResultViewer")
    result_marked = Signal(SSUResult)

    def __init__(self, reference_viewer: ReferenceResultViewer, parent=None):
        super().__init__(parent=parent, f=Qt.Window)
        self.setWindowTitle(self.tr("SSU Fitting Result Viewer"))
        self.__fitting_results = []  # type: list[SSUResult]
        self.retry_tasks = {}  # type: dict[UUID, SSUTask]
        self.__reference_viewer = reference_viewer
        self.init_ui()
        self.boxplot_chart = BoxplotChart(parent=self, toolbar=True)
        self.typical_chart = SSUTypicalComponentChart(parent=self,
                                                      toolbar=True)
        self.distance_chart = DistanceCurveChart(parent=self, toolbar=True)
        self.mixed_distribution_chart = MixedDistributionChart(
            parent=self, toolbar=True, use_animation=True)
        self.file_dialog = QFileDialog(parent=self)
        self.async_worker = AsyncWorker()
        self.async_worker.background_worker.task_succeeded.connect(
            self.on_fitting_succeeded)
        self.async_worker.background_worker.task_failed.connect(
            self.on_fitting_failed)
        self.update_page_list()
        self.update_page(self.page_index)

        self.normal_msg = QMessageBox(self)
        self.remove_warning_msg = QMessageBox(self)
        self.remove_warning_msg.setStandardButtons(QMessageBox.No
                                                   | QMessageBox.Yes)
        self.remove_warning_msg.setDefaultButton(QMessageBox.No)
        self.remove_warning_msg.setWindowTitle(self.tr("Warning"))
        self.remove_warning_msg.setText(
            self.tr("Are you sure to remove all SSU results?"))
        self.outlier_msg = QMessageBox(self)
        self.outlier_msg.setStandardButtons(QMessageBox.Discard
                                            | QMessageBox.Retry
                                            | QMessageBox.Ignore)
        self.outlier_msg.setDefaultButton(QMessageBox.Ignore)
        self.retry_progress_msg = QMessageBox()
        self.retry_progress_msg.addButton(QMessageBox.Ok)
        self.retry_progress_msg.button(QMessageBox.Ok).hide()
        self.retry_progress_msg.setWindowTitle(self.tr("Progress"))
        self.retry_timer = QTimer(self)
        self.retry_timer.setSingleShot(True)
        self.retry_timer.timeout.connect(
            lambda: self.retry_progress_msg.exec_())

    def init_ui(self):
        self.data_table = QTableWidget(100, 100)
        self.data_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.data_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.data_table.setAlternatingRowColors(True)
        self.data_table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.data_table, 0, 0, 1, 3)

        self.previous_button = QPushButton(
            qta.icon("mdi.skip-previous-circle"), self.tr("Previous"))
        self.previous_button.setToolTip(
            self.tr("Click to back to the previous page."))
        self.previous_button.clicked.connect(self.on_previous_button_clicked)
        self.current_page_combo_box = QComboBox()
        self.current_page_combo_box.addItem(self.tr("Page {0}").format(1))
        self.current_page_combo_box.currentIndexChanged.connect(
            self.update_page)
        self.next_button = QPushButton(qta.icon("mdi.skip-next-circle"),
                                       self.tr("Next"))
        self.next_button.setToolTip(self.tr("Click to jump to the next page."))
        self.next_button.clicked.connect(self.on_next_button_clicked)
        self.main_layout.addWidget(self.previous_button, 1, 0)
        self.main_layout.addWidget(self.current_page_combo_box, 1, 1)
        self.main_layout.addWidget(self.next_button, 1, 2)

        self.distance_label = QLabel(self.tr("Distance"))
        self.distance_label.setToolTip(
            self.
            tr("It's the function to calculate the difference (on the contrary, similarity) between two samples."
               ))
        self.distance_combo_box = QComboBox()
        self.distance_combo_box.addItems(built_in_distances)
        self.distance_combo_box.setCurrentText("log10MSE")
        self.distance_combo_box.currentTextChanged.connect(
            lambda: self.update_page(self.page_index))
        self.main_layout.addWidget(self.distance_label, 2, 0)
        self.main_layout.addWidget(self.distance_combo_box, 2, 1, 1, 2)
        self.menu = QMenu(self.data_table)
        self.menu.setShortcutAutoRepeat(True)
        self.mark_action = self.menu.addAction(
            qta.icon("mdi.marker-check"),
            self.tr("Mark Selection(s) as Reference"))
        self.mark_action.triggered.connect(self.mark_selections)
        self.remove_selection_action = self.menu.addAction(
            qta.icon("fa.remove"), self.tr("Remove Selection(s)"))
        self.remove_selection_action.triggered.connect(self.remove_selections)
        self.remove_all_action = self.menu.addAction(qta.icon("fa.remove"),
                                                     self.tr("Remove All"))
        self.remove_all_action.triggered.connect(self.remove_all_results)
        self.plot_loss_chart_action = self.menu.addAction(
            qta.icon("mdi.chart-timeline-variant"), self.tr("Plot Loss Chart"))
        self.plot_loss_chart_action.triggered.connect(self.show_distance)
        self.plot_distribution_chart_action = self.menu.addAction(
            qta.icon("fa5s.chart-area"), self.tr("Plot Distribution Chart"))
        self.plot_distribution_chart_action.triggered.connect(
            self.show_distribution)
        self.plot_distribution_animation_action = self.menu.addAction(
            qta.icon("fa5s.chart-area"),
            self.tr("Plot Distribution Chart (Animation)"))
        self.plot_distribution_animation_action.triggered.connect(
            self.show_history_distribution)

        self.detect_outliers_menu = self.menu.addMenu(
            qta.icon("mdi.magnify"), self.tr("Detect Outliers"))
        self.check_nan_and_inf_action = self.detect_outliers_menu.addAction(
            self.tr("Check NaN and Inf"))
        self.check_nan_and_inf_action.triggered.connect(self.check_nan_and_inf)
        self.check_final_distances_action = self.detect_outliers_menu.addAction(
            self.tr("Check Final Distances"))
        self.check_final_distances_action.triggered.connect(
            self.check_final_distances)
        self.check_component_mean_action = self.detect_outliers_menu.addAction(
            self.tr("Check Component Mean"))
        self.check_component_mean_action.triggered.connect(
            lambda: self.check_component_moments("mean"))
        self.check_component_std_action = self.detect_outliers_menu.addAction(
            self.tr("Check Component STD"))
        self.check_component_std_action.triggered.connect(
            lambda: self.check_component_moments("std"))
        self.check_component_skewness_action = self.detect_outliers_menu.addAction(
            self.tr("Check Component Skewness"))
        self.check_component_skewness_action.triggered.connect(
            lambda: self.check_component_moments("skewness"))
        self.check_component_kurtosis_action = self.detect_outliers_menu.addAction(
            self.tr("Check Component Kurtosis"))
        self.check_component_kurtosis_action.triggered.connect(
            lambda: self.check_component_moments("kurtosis"))
        self.check_component_fractions_action = self.detect_outliers_menu.addAction(
            self.tr("Check Component Fractions"))
        self.check_component_fractions_action.triggered.connect(
            self.check_component_fractions)
        self.degrade_results_action = self.detect_outliers_menu.addAction(
            self.tr("Degrade Results"))
        self.degrade_results_action.triggered.connect(self.degrade_results)
        self.try_align_components_action = self.detect_outliers_menu.addAction(
            self.tr("Try Align Components"))
        self.try_align_components_action.triggered.connect(
            self.try_align_components)

        self.analyse_typical_components_action = self.menu.addAction(
            qta.icon("ei.tags"), self.tr("Analyse Typical Components"))
        self.analyse_typical_components_action.triggered.connect(
            self.analyse_typical_components)
        self.load_dump_action = self.menu.addAction(
            qta.icon("fa.database"), self.tr("Load Binary Dump"))
        self.load_dump_action.triggered.connect(self.load_dump)
        self.save_dump_action = self.menu.addAction(
            qta.icon("fa.save"), self.tr("Save Binary Dump"))
        self.save_dump_action.triggered.connect(self.save_dump)
        self.save_excel_action = self.menu.addAction(
            qta.icon("mdi.microsoft-excel"), self.tr("Save Excel"))
        self.save_excel_action.triggered.connect(
            lambda: self.on_save_excel_clicked(align_components=False))
        self.save_excel_align_action = self.menu.addAction(
            qta.icon("mdi.microsoft-excel"),
            self.tr("Save Excel (Force Alignment)"))
        self.save_excel_align_action.triggered.connect(
            lambda: self.on_save_excel_clicked(align_components=True))
        self.data_table.customContextMenuRequested.connect(self.show_menu)
        # necessary to add actions of menu to this widget itself,
        # otherwise, the shortcuts will not be triggered
        self.addActions(self.menu.actions())

    def show_menu(self, pos: QPoint):
        self.menu.popup(QCursor.pos())

    def show_message(self, title: str, message: str):
        self.normal_msg.setWindowTitle(title)
        self.normal_msg.setText(message)
        self.normal_msg.exec_()

    def show_info(self, message: str):
        self.show_message(self.tr("Info"), message)

    def show_warning(self, message: str):
        self.show_message(self.tr("Warning"), message)

    def show_error(self, message: str):
        self.show_message(self.tr("Error"), message)

    @property
    def distance_name(self) -> str:
        return self.distance_combo_box.currentText()

    @property
    def distance_func(self) -> typing.Callable:
        return get_distance_func_by_name(self.distance_combo_box.currentText())

    @property
    def page_index(self) -> int:
        return self.current_page_combo_box.currentIndex()

    @property
    def n_pages(self) -> int:
        return self.current_page_combo_box.count()

    @property
    def n_results(self) -> int:
        return len(self.__fitting_results)

    @property
    def selections(self):
        start = self.page_index * self.PAGE_ROWS
        temp = set()
        for item in self.data_table.selectedRanges():
            for i in range(item.topRow(),
                           min(self.PAGE_ROWS + 1,
                               item.bottomRow() + 1)):
                temp.add(i + start)
        indexes = list(temp)
        indexes.sort()
        return indexes

    def update_page_list(self):
        last_page_index = self.page_index
        if self.n_results == 0:
            n_pages = 1
        else:
            n_pages, left = divmod(self.n_results, self.PAGE_ROWS)
            if left != 0:
                n_pages += 1
        self.current_page_combo_box.blockSignals(True)
        self.current_page_combo_box.clear()
        self.current_page_combo_box.addItems(
            [self.tr("Page {0}").format(i + 1) for i in range(n_pages)])
        if last_page_index >= n_pages:
            self.current_page_combo_box.setCurrentIndex(n_pages - 1)
        else:
            self.current_page_combo_box.setCurrentIndex(last_page_index)
        self.current_page_combo_box.blockSignals(False)

    def update_page(self, page_index: int):
        def write(row: int, col: int, value: str):
            if isinstance(value, str):
                pass
            elif isinstance(value, int):
                value = str(value)
            elif isinstance(value, float):
                value = f"{value: 0.4f}"
            else:
                value = value.__str__()
            item = QTableWidgetItem(value)
            item.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, col, item)

        # necessary to clear
        self.data_table.clear()
        if page_index == self.n_pages - 1:
            start = page_index * self.PAGE_ROWS
            end = self.n_results
        else:
            start, end = page_index * self.PAGE_ROWS, (page_index +
                                                       1) * self.PAGE_ROWS
        self.data_table.setRowCount(end - start)
        self.data_table.setColumnCount(7)
        self.data_table.setHorizontalHeaderLabels([
            self.tr("Resolver"),
            self.tr("Distribution Type"),
            self.tr("N_components"),
            self.tr("N_iterations"),
            self.tr("Spent Time [s]"),
            self.tr("Final Distance"),
            self.tr("Has Reference")
        ])
        sample_names = [
            result.sample.name for result in self.__fitting_results[start:end]
        ]
        self.data_table.setVerticalHeaderLabels(sample_names)
        for row, result in enumerate(self.__fitting_results[start:end]):
            write(row, 0, result.task.resolver)
            write(row, 1,
                  self.get_distribution_name(result.task.distribution_type))
            write(row, 2, result.task.n_components)
            write(row, 3, result.n_iterations)
            write(row, 4, result.time_spent)
            write(
                row, 5,
                self.distance_func(result.sample.distribution,
                                   result.distribution))
            has_ref = result.task.initial_guess is not None or result.task.reference is not None
            write(row, 6, self.tr("Yes") if has_ref else self.tr("No"))

        self.data_table.resizeColumnsToContents()

    def on_previous_button_clicked(self):
        if self.page_index > 0:
            self.current_page_combo_box.setCurrentIndex(self.page_index - 1)

    def on_next_button_clicked(self):
        if self.page_index < self.n_pages - 1:
            self.current_page_combo_box.setCurrentIndex(self.page_index + 1)

    def get_distribution_name(self, distribution_type: DistributionType):
        if distribution_type == DistributionType.Normal:
            return self.tr("Normal")
        elif distribution_type == DistributionType.Weibull:
            return self.tr("Weibull")
        elif distribution_type == DistributionType.SkewNormal:
            return self.tr("Skew Normal")
        else:
            raise NotImplementedError(distribution_type)

    def add_result(self, result: SSUResult):
        if self.n_results == 0 or \
            (self.page_index == self.n_pages - 1 and \
            divmod(self.n_results, self.PAGE_ROWS)[-1] != 0):
            need_update = True
        else:
            need_update = False
        self.__fitting_results.append(result)
        self.update_page_list()
        if need_update:
            self.update_page(self.page_index)

    def add_results(self, results: typing.List[SSUResult]):
        if self.n_results == 0 or \
            (self.page_index == self.n_pages - 1 and \
            divmod(self.n_results, self.PAGE_ROWS)[-1] != 0):
            need_update = True
        else:
            need_update = False
        self.__fitting_results.extend(results)
        self.update_page_list()
        if need_update:
            self.update_page(self.page_index)

    def mark_selections(self):
        for index in self.selections:
            self.result_marked.emit(self.__fitting_results[index])

    def remove_results(self, indexes):
        results = []
        for i in reversed(indexes):
            res = self.__fitting_results.pop(i)
            results.append(res)
        self.update_page_list()
        self.update_page(self.page_index)

    def remove_selections(self):
        indexes = self.selections
        self.remove_results(indexes)

    def remove_all_results(self):
        res = self.remove_warning_msg.exec_()
        if res == QMessageBox.Yes:
            self.__fitting_results.clear()
            self.update_page_list()
            self.update_page(0)

    def show_distance(self):
        results = [self.__fitting_results[i] for i in self.selections]
        if results is None or len(results) == 0:
            return
        result = results[0]
        self.distance_chart.show_distance_series(result.get_distance_series(
            self.distance_name),
                                                 title=result.sample.name)
        self.distance_chart.show()

    def show_distribution(self):
        results = [self.__fitting_results[i] for i in self.selections]
        if results is None or len(results) == 0:
            return
        result = results[0]
        self.mixed_distribution_chart.show_model(result.view_model)
        self.mixed_distribution_chart.show()

    def show_history_distribution(self):
        results = [self.__fitting_results[i] for i in self.selections]
        if results is None or len(results) == 0:
            return
        result = results[0]
        self.mixed_distribution_chart.show_result(result)
        self.mixed_distribution_chart.show()

    def load_dump(self):
        filename, _ = self.file_dialog.getOpenFileName(
            self, self.tr("Select a binary dump file of SSU results"), None,
            self.tr("Binary dump (*.dump)"))
        if filename is None or filename == "":
            return
        with open(filename, "rb") as f:
            results = pickle.load(f)  # type: list[SSUResult]
            valid = True
            if isinstance(results, list):
                for result in results:
                    if not isinstance(result, SSUResult):
                        valid = False
                        break
            else:
                valid = False

            if valid:
                if self.n_results != 0 and len(results) != 0:
                    old_classes = self.__fitting_results[0].classes_φ
                    new_classes = results[0].classes_φ
                    classes_inconsistent = False
                    if len(old_classes) != len(new_classes):
                        classes_inconsistent = True
                    else:
                        classes_error = np.abs(old_classes - new_classes)
                        if not np.all(np.less_equal(classes_error, 1e-8)):
                            classes_inconsistent = True
                    if classes_inconsistent:
                        self.show_error(
                            self.
                            tr("The results in the dump file has inconsistent grain-size classes with that in your list."
                               ))
                        return
                self.add_results(results)
            else:
                self.show_error(self.tr("The binary dump file is invalid."))

    def save_dump(self):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        filename, _ = self.file_dialog.getSaveFileName(
            self, self.tr("Save the SSU results to binary dump file"), None,
            self.tr("Binary dump (*.dump)"))
        if filename is None or filename == "":
            return
        with open(filename, "wb") as f:
            pickle.dump(self.__fitting_results, f)

    def save_excel(self, filename, align_components=False):
        if self.n_results == 0:
            return

        results = self.__fitting_results.copy()
        classes_μm = results[0].classes_μm
        n_components_list = [
            result.n_components for result in self.__fitting_results
        ]
        count_dict = Counter(n_components_list)
        max_n_components = max(count_dict.keys())
        self.logger.debug(
            f"N_components: {count_dict}, Max N_components: {max_n_components}"
        )

        flags = []
        if not align_components:
            for result in results:
                flags.extend(range(result.n_components))
        else:
            n_components_desc = "\n".join([
                self.tr("{0} Component(s): {1}").format(n_components, count)
                for n_components, count in count_dict.items()
            ])
            self.show_info(
                self.tr("N_components distribution of Results:\n{0}").format(
                    n_components_desc))
            stacked_components = []
            for result in self.__fitting_results:
                for component in result.components:
                    stacked_components.append(component.distribution)
            stacked_components = np.array(stacked_components)
            cluser = KMeans(n_clusters=max_n_components)
            flags = cluser.fit_predict(stacked_components)
            # check flags to make it unique
            flag_index = 0
            for i, result in enumerate(self.__fitting_results):
                result_flags = set()
                for component in result.components:
                    if flags[flag_index] in result_flags:
                        if flags[flag_index] == max_n_components:
                            flags[flag_index] = max_n_components - 1
                        else:
                            flag_index[flag_index] += 1
                        result_flags.add(flags[flag_index])
                    flag_index += 1

            flag_set = set(flags)
            picked = []
            for target_flag in flag_set:
                for i, flag in enumerate(flags):
                    if flag == target_flag:
                        picked.append(
                            (target_flag,
                             logarithmic(classes_μm,
                                         stacked_components[i])["mean"]))
                        break
            picked.sort(key=lambda x: x[1])
            flag_map = {flag: index for index, (flag, _) in enumerate(picked)}
            flags = np.array([flag_map[flag] for flag in flags])

        wb = openpyxl.Workbook()
        prepare_styles(wb)
        ws = wb.active
        ws.title = self.tr("README")
        description = \
            """
            This Excel file was generated by QGrain ({0}).

            Please cite:
            Liu, Y., Liu, X., Sun, Y., 2021. QGrain: An open-source and easy-to-use software for the comprehensive analysis of grain size distributions. Sedimentary Geology 423, 105980. https://doi.org/10.1016/j.sedgeo.2021.105980

            It contanins 4 + max(N_components) sheets:
            1. The first sheet is the sample distributions of SSU results.
            2. The second sheet is used to put the infomation of fitting.
            3. The third sheet is the statistic parameters calculated by statistic moment method.
            4. The fouth sheet is the distributions of unmixed components and their sum of each sample.
            5. Other sheets are the unmixed end-member distributions which were discretely stored.

            The SSU algorithm is implemented by QGrain.

            """.format(QGRAIN_VERSION)

        def write(row, col, value, style="normal_light"):
            cell = ws.cell(row + 1, col + 1, value=value)
            cell.style = style

        lines_of_desc = description.split("\n")
        for row, line in enumerate(lines_of_desc):
            write(row, 0, line, style="description")
        ws.column_dimensions[column_to_char(0)].width = 200

        ws = wb.create_sheet(self.tr("Sample Distributions"))
        write(0, 0, self.tr("Sample Name"), style="header")
        ws.column_dimensions[column_to_char(0)].width = 16
        for col, value in enumerate(classes_μm, 1):
            write(0, col, value, style="header")
            ws.column_dimensions[column_to_char(col)].width = 10
        for row, result in enumerate(results, 1):
            if row % 2 == 0:
                style = "normal_dark"
            else:
                style = "normal_light"
            write(row, 0, result.sample.name, style=style)
            for col, value in enumerate(result.sample.distribution, 1):
                write(row, col, value, style=style)
            QCoreApplication.processEvents()

        ws = wb.create_sheet(self.tr("Information of Fitting"))
        write(0, 0, self.tr("Sample Name"), style="header")
        ws.column_dimensions[column_to_char(0)].width = 16
        headers = [
            self.tr("Distribution Type"),
            self.tr("N_components"),
            self.tr("Resolver"),
            self.tr("Resolver Settings"),
            self.tr("Initial Guess"),
            self.tr("Reference"),
            self.tr("Spent Time [s]"),
            self.tr("N_iterations"),
            self.tr("Final Distance [log10MSE]")
        ]
        for col, value in enumerate(headers, 1):
            write(0, col, value, style="header")
            if col in (4, 5, 6):
                ws.column_dimensions[column_to_char(col)].width = 10
            else:
                ws.column_dimensions[column_to_char(col)].width = 10
        for row, result in enumerate(results, 1):
            if row % 2 == 0:
                style = "normal_dark"
            else:
                style = "normal_light"
            write(row, 0, result.sample.name, style=style)
            write(row, 1, result.distribution_type.name, style=style)
            write(row, 2, result.n_components, style=style)
            write(row, 3, result.task.resolver, style=style)
            write(row,
                  4,
                  self.tr("Default") if result.task.resolver_setting is None
                  else result.task.resolver_setting.__str__(),
                  style=style)
            write(row,
                  5,
                  self.tr("None") if result.task.initial_guess is None else
                  result.task.initial_guess.__str__(),
                  style=style)
            write(row,
                  6,
                  self.tr("None") if result.task.reference is None else
                  result.task.reference.__str__(),
                  style=style)
            write(row, 7, result.time_spent, style=style)
            write(row, 8, result.n_iterations, style=style)
            write(row, 9, result.get_distance("log10MSE"), style=style)

        ws = wb.create_sheet(self.tr("Statistic Moments"))
        write(0, 0, self.tr("Sample Name"), style="header")
        ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1)
        ws.column_dimensions[column_to_char(0)].width = 16
        headers = []
        sub_headers = [
            self.tr("Proportion"),
            self.tr("Mean [φ]"),
            self.tr("Mean [μm]"),
            self.tr("STD [φ]"),
            self.tr("STD [μm]"),
            self.tr("Skewness"),
            self.tr("Kurtosis")
        ]
        for i in range(max_n_components):
            write(0,
                  i * len(sub_headers) + 1,
                  self.tr("C{0}").format(i + 1),
                  style="header")
            ws.merge_cells(start_row=1,
                           start_column=i * len(sub_headers) + 2,
                           end_row=1,
                           end_column=(i + 1) * len(sub_headers) + 1)
            headers.extend(sub_headers)
        for col, value in enumerate(headers, 1):
            write(1, col, value, style="header")
            ws.column_dimensions[column_to_char(col)].width = 10
        flag_index = 0
        for row, result in enumerate(results, 2):
            if row % 2 == 0:
                style = "normal_light"
            else:
                style = "normal_dark"
            write(row, 0, result.sample.name, style=style)
            for component in result.components:
                index = flags[flag_index]
                write(row,
                      index * len(sub_headers) + 1,
                      component.fraction,
                      style=style)
                write(row,
                      index * len(sub_headers) + 2,
                      component.logarithmic_moments["mean"],
                      style=style)
                write(row,
                      index * len(sub_headers) + 3,
                      component.geometric_moments["mean"],
                      style=style)
                write(row,
                      index * len(sub_headers) + 4,
                      component.logarithmic_moments["std"],
                      style=style)
                write(row,
                      index * len(sub_headers) + 5,
                      component.geometric_moments["std"],
                      style=style)
                write(row,
                      index * len(sub_headers) + 6,
                      component.logarithmic_moments["skewness"],
                      style=style)
                write(row,
                      index * len(sub_headers) + 7,
                      component.logarithmic_moments["kurtosis"],
                      style=style)
                flag_index += 1

        ws = wb.create_sheet(self.tr("Unmixed Components"))
        ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=2)
        write(0, 0, self.tr("Sample Name"), style="header")
        ws.column_dimensions[column_to_char(0)].width = 16
        for col, value in enumerate(classes_μm, 2):
            write(0, col, value, style="header")
            ws.column_dimensions[column_to_char(col)].width = 10
        row = 1
        for result_index, result in enumerate(results, 1):
            if result_index % 2 == 0:
                style = "normal_dark"
            else:
                style = "normal_light"
            write(row, 0, result.sample.name, style=style)
            ws.merge_cells(start_row=row + 1,
                           start_column=1,
                           end_row=row + result.n_components + 1,
                           end_column=1)
            for component_i, component in enumerate(result.components, 1):
                write(row, 1, self.tr("C{0}").format(component_i), style=style)
                for col, value in enumerate(
                        component.distribution * component.fraction, 2):
                    write(row, col, value, style=style)
                row += 1
            write(row, 1, self.tr("Sum"), style=style)
            for col, value in enumerate(result.distribution, 2):
                write(row, col, value, style=style)
            row += 1

        ws_dict = {}
        flag_set = set(flags)
        for flag in flag_set:
            ws = wb.create_sheet(self.tr("Unmixed EM{0}").format(flag + 1))
            write(0, 0, self.tr("Sample Name"), style="header")
            ws.column_dimensions[column_to_char(0)].width = 16
            for col, value in enumerate(classes_μm, 1):
                write(0, col, value, style="header")
                ws.column_dimensions[column_to_char(col)].width = 10
            ws_dict[flag] = ws

        flag_index = 0
        for row, result in enumerate(results, 1):
            if row % 2 == 0:
                style = "normal_dark"
            else:
                style = "normal_light"

            for component in result.components:
                flag = flags[flag_index]
                ws = ws_dict[flag]
                write(row, 0, result.sample.name, style=style)
                for col, value in enumerate(component.distribution, 1):
                    write(row, col, value, style=style)
                flag_index += 1

        wb.save(filename)
        wb.close()

    def on_save_excel_clicked(self, align_components=False):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any SSU result."))
            return
        filename, _ = self.file_dialog.getSaveFileName(
            None, self.tr("Choose a filename to save SSU Results"), None,
            "Microsoft Excel (*.xlsx)")
        if filename is None or filename == "":
            return
        try:
            self.save_excel(filename, align_components)
            self.show_info(
                self.tr("SSU results have been saved to:\n    {0}").format(
                    filename))
        except Exception as e:
            self.show_error(
                self.
                tr("Error raised while save SSU results to Excel file.\n    {0}"
                   ).format(e.__str__()))

    def on_fitting_succeeded(self, result: SSUResult):
        result_replace_index = self.retry_tasks[result.task.uuid]
        self.__fitting_results[result_replace_index] = result
        self.retry_tasks.pop(result.task.uuid)
        self.retry_progress_msg.setText(
            self.tr("Tasks to be retried: {0}").format(len(self.retry_tasks)))
        if len(self.retry_tasks) == 0:
            self.retry_progress_msg.close()

        self.logger.debug(
            f"Retried task succeeded, sample name={result.task.sample.name}, distribution_type={result.task.distribution_type.name}, n_components={result.task.n_components}"
        )
        self.update_page(self.page_index)

    def on_fitting_failed(self, failed_info: str, task: SSUTask):
        # necessary to remove it from the dict
        self.retry_tasks.pop(task.uuid)
        if len(self.retry_tasks) == 0:
            self.retry_progress_msg.close()
        self.show_error(
            self.tr("Failed to retry task, sample name={0}.\n{1}").format(
                task.sample.name, failed_info))
        self.logger.warning(
            f"Failed to retry task, sample name={task.sample.name}, distribution_type={task.distribution_type.name}, n_components={task.n_components}"
        )

    def retry_results(self, indexes, results):
        assert len(indexes) == len(results)
        if len(results) == 0:
            return
        self.retry_progress_msg.setText(
            self.tr("Tasks to be retried: {0}").format(len(results)))
        self.retry_timer.start(1)
        for index, result in zip(indexes, results):
            query = self.__reference_viewer.query_reference(result.sample)
            ref_result = None
            if query is None:
                nearby_results = self.__fitting_results[
                    index - 5:index] + self.__fitting_results[index + 1:index +
                                                              6]
                ref_result = self.__reference_viewer.find_similar(
                    result.sample, nearby_results)
            else:
                ref_result = query
            keys = ["mean", "std", "skewness"]
            # reference = [{key: comp.logarithmic_moments[key] for key in keys} for comp in ref_result.components]
            task = SSUTask(
                result.sample,
                ref_result.distribution_type,
                ref_result.n_components,
                resolver=ref_result.task.resolver,
                resolver_setting=ref_result.task.resolver_setting,
                #    reference=reference)
                initial_guess=ref_result.last_func_args)

            self.logger.debug(
                f"Retry task: sample name={task.sample.name}, distribution_type={task.distribution_type.name}, n_components={task.n_components}"
            )
            self.retry_tasks[task.uuid] = index
            self.async_worker.execute_task(task)

    def degrade_results(self):
        degrade_results = []  # type: list[SSUResult]
        degrade_indexes = []  # type: list[int]
        for i, result in enumerate(self.__fitting_results):
            for component in result.components:
                if component.fraction < 1e-3:
                    degrade_results.append(result)
                    degrade_indexes.append(i)
                    break
        self.logger.debug(
            f"Results should be degrade (have a redundant component): {[result.sample.name for result in degrade_results]}"
        )
        if len(degrade_results) == 0:
            self.show_info(
                self.tr("No fitting result was evaluated as an outlier."))
            return
        self.show_info(
            self.
            tr("The results below should be degrade (have a redundant component:\n    {0}"
               ).format(", ".join(
                   [result.sample.name for result in degrade_results])))

        self.retry_progress_msg.setText(
            self.tr("Tasks to be retried: {0}").format(len(degrade_results)))
        self.retry_timer.start(1)
        for index, result in zip(degrade_indexes, degrade_results):
            reference = []
            n_redundant = 0
            for component in result.components:
                if component.fraction < 1e-3:
                    n_redundant += 1
                else:
                    reference.append(
                        dict(mean=component.logarithmic_moments["mean"],
                             std=component.logarithmic_moments["std"],
                             skewness=component.logarithmic_moments["skewness"]
                             ))
            task = SSUTask(
                result.sample,
                result.distribution_type,
                result.n_components -
                n_redundant if result.n_components > n_redundant else 1,
                resolver=result.task.resolver,
                resolver_setting=result.task.resolver_setting,
                reference=reference)
            self.logger.debug(
                f"Retry task: sample name={task.sample.name}, distribution_type={task.distribution_type.name}, n_components={task.n_components}"
            )
            self.retry_tasks[task.uuid] = index
            self.async_worker.execute_task(task)

    def ask_deal_outliers(self, outlier_results: typing.List[SSUResult],
                          outlier_indexes: typing.List[int]):
        assert len(outlier_indexes) == len(outlier_results)
        if len(outlier_results) == 0:
            self.show_info(
                self.tr("No fitting result was evaluated as an outlier."))
        else:
            if len(outlier_results) > 100:
                self.outlier_msg.setText(
                    self.
                    tr("The fitting results have the component that its fraction is near zero:\n    {0}...(total {1} outliers)\nHow to deal with them?"
                       ).format(
                           ", ".join([
                               result.sample.name
                               for result in outlier_results[:100]
                           ]), len(outlier_results)))
            else:
                self.outlier_msg.setText(
                    self.
                    tr("The fitting results have the component that its fraction is near zero:\n    {0}\nHow to deal with them?"
                       ).format(", ".join([
                           result.sample.name for result in outlier_results
                       ])))
            res = self.outlier_msg.exec_()
            if res == QMessageBox.Discard:
                self.remove_results(outlier_indexes)
            elif res == QMessageBox.Retry:
                self.retry_results(outlier_indexes, outlier_results)
            else:
                pass

    def check_nan_and_inf(self):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        outlier_results = []
        outlier_indexes = []
        for i, result in enumerate(self.__fitting_results):
            if not result.is_valid:
                outlier_results.append(result)
                outlier_indexes.append(i)
        self.logger.debug(
            f"Outlier results with the nan or inf value(s): {[result.sample.name for result in outlier_results]}"
        )
        self.ask_deal_outliers(outlier_results, outlier_indexes)

    def check_final_distances(self):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        elif self.n_results < 10:
            self.show_warning(self.tr("The results in list are too less."))
            return
        distances = []
        for result in self.__fitting_results:
            distances.append(result.get_distance(self.distance_name))
        distances = np.array(distances)
        self.boxplot_chart.show_dataset([distances],
                                        xlabels=[self.distance_name],
                                        ylabel=self.tr("Distance"))
        self.boxplot_chart.show()

        # calculate the 1/4, 1/2, and 3/4 postion value to judge which result is invalid
        # 1. the mean squared errors are much higher in the results which are lack of components
        # 2. with the component number getting higher, the mean squared error will get lower and finally reach the minimum
        median = np.median(distances)
        upper_group = distances[np.greater(distances, median)]
        lower_group = distances[np.less(distances, median)]
        value_1_4 = np.median(lower_group)
        value_3_4 = np.median(upper_group)
        distance_QR = value_3_4 - value_1_4
        outlier_results = []
        outlier_indexes = []
        for i, (result,
                distance) in enumerate(zip(self.__fitting_results, distances)):
            if distance > value_3_4 + distance_QR * 1.5:
                # which error too small is not outlier
                # if distance > value_3_4 + distance_QR * 1.5 or distance < value_1_4 - distance_QR * 1.5:
                outlier_results.append(result)
                outlier_indexes.append(i)
        self.logger.debug(
            f"Outlier results with too greater distances: {[result.sample.name for result in outlier_results]}"
        )
        self.ask_deal_outliers(outlier_results, outlier_indexes)

    def check_component_moments(self, key: str):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        elif self.n_results < 10:
            self.show_warning(self.tr("The results in list are too less."))
            return
        max_n_components = 0
        for result in self.__fitting_results:
            if result.n_components > max_n_components:
                max_n_components = result.n_components
        moments = []
        for i in range(max_n_components):
            moments.append([])

        for result in self.__fitting_results:
            for i, component in enumerate(result.components):
                if np.isnan(component.logarithmic_moments[key]) or np.isinf(
                        component.logarithmic_moments[key]):
                    pass
                else:
                    moments[i].append(component.logarithmic_moments[key])

        # key_trans = {"mean": self.tr("Mean"), "std": self.tr("STD"), "skewness": self.tr("Skewness"), "kurtosis": self.tr("Kurtosis")}
        key_label_trans = {
            "mean": self.tr("Mean [φ]"),
            "std": self.tr("STD [φ]"),
            "skewness": self.tr("Skewness"),
            "kurtosis": self.tr("Kurtosis")
        }
        self.boxplot_chart.show_dataset(
            moments,
            xlabels=[f"C{i+1}" for i in range(max_n_components)],
            ylabel=key_label_trans[key])
        self.boxplot_chart.show()

        outlier_dict = {}

        for i in range(max_n_components):
            stacked_moments = np.array(moments[i])
            # calculate the 1/4, 1/2, and 3/4 postion value to judge which result is invalid
            # 1. the mean squared errors are much higher in the results which are lack of components
            # 2. with the component number getting higher, the mean squared error will get lower and finally reach the minimum
            median = np.median(stacked_moments)
            upper_group = stacked_moments[np.greater(stacked_moments, median)]
            lower_group = stacked_moments[np.less(stacked_moments, median)]
            value_1_4 = np.median(lower_group)
            value_3_4 = np.median(upper_group)
            distance_QR = value_3_4 - value_1_4

            for j, result in enumerate(self.__fitting_results):
                if result.n_components > i:
                    distance = result.components[i].logarithmic_moments[key]
                    if distance > value_3_4 + distance_QR * 1.5 or distance < value_1_4 - distance_QR * 1.5:
                        outlier_dict[j] = result

        outlier_results = []
        outlier_indexes = []
        for index, result in sorted(outlier_dict.items(), key=lambda x: x[0]):
            outlier_indexes.append(index)
            outlier_results.append(result)
        self.logger.debug(
            f"Outlier results with abnormal {key} values of their components: {[result.sample.name for result in outlier_results]}"
        )
        self.ask_deal_outliers(outlier_results, outlier_indexes)

    def check_component_fractions(self):
        outlier_results = []
        outlier_indexes = []
        for i, result in enumerate(self.__fitting_results):
            for component in result.components:
                if component.fraction < 1e-3:
                    outlier_results.append(result)
                    outlier_indexes.append(i)
                    break
        self.logger.debug(
            f"Outlier results with the component that its fraction is near zero: {[result.sample.name for result in outlier_results]}"
        )
        self.ask_deal_outliers(outlier_results, outlier_indexes)

    def try_align_components(self):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        elif self.n_results < 10:
            self.show_warning(self.tr("The results in list are too less."))
            return
        import matplotlib.pyplot as plt
        n_components_list = [
            result.n_components for result in self.__fitting_results
        ]
        count_dict = Counter(n_components_list)
        max_n_components = max(count_dict.keys())
        self.logger.debug(
            f"N_components: {count_dict}, Max N_components: {max_n_components}"
        )
        n_components_desc = "\n".join([
            self.tr("{0} Component(s): {1}").format(n_components, count)
            for n_components, count in count_dict.items()
        ])
        self.show_info(
            self.tr("N_components distribution of Results:\n{0}").format(
                n_components_desc))

        x = self.__fitting_results[0].classes_μm
        stacked_components = []
        for result in self.__fitting_results:
            for component in result.components:
                stacked_components.append(component.distribution)
        stacked_components = np.array(stacked_components)

        cluser = KMeans(n_clusters=max_n_components)
        flags = cluser.fit_predict(stacked_components)

        figure = plt.figure(figsize=(6, 4))
        cmap = plt.get_cmap("tab10")
        axes = figure.add_subplot(1, 1, 1)
        for flag, distribution in zip(flags, stacked_components):
            plt.plot(x, distribution, c=cmap(flag), zorder=flag)
        axes.set_xscale("log")
        axes.set_xlabel(self.tr("Grain-size [μm]"))
        axes.set_ylabel(self.tr("Frequency"))
        figure.tight_layout()
        figure.show()

        outlier_results = []
        outlier_indexes = []
        flag_index = 0
        for i, result in enumerate(self.__fitting_results):
            result_flags = set()
            for component in result.components:
                if flags[flag_index] in result_flags:
                    outlier_results.append(result)
                    outlier_indexes.append(i)
                    break
                else:
                    result_flags.add(flags[flag_index])
                flag_index += 1
        self.logger.debug(
            f"Outlier results that have two components in the same cluster: {[result.sample.name for result in outlier_results]}"
        )
        self.ask_deal_outliers(outlier_results, outlier_indexes)

    def analyse_typical_components(self):
        if self.n_results == 0:
            self.show_warning(self.tr("There is not any result in the list."))
            return
        elif self.n_results < 10:
            self.show_warning(self.tr("The results in list are too less."))
            return

        self.typical_chart.show_typical(self.__fitting_results)
        self.typical_chart.show()
Пример #42
0
 def on_save_project_triggered(self):
     file_name = QFileDialog.getSaveFileName(
         self, 'select location and give file name', '../saves',
         'Ryven Project(*.rpo)')[0]
     if file_name != '':
         self.save_project(file_name)