Ejemplo n.º 1
0
class VisualizationConnection(QWidget, Ui_Visualization):
    def __init__(self, parent=None):
        self._root_folder = ''
        self._fae = FeatureAnalysisPipelines()
        self.sheet_dict = dict()
        self.logger = eclog(os.path.split(__file__)[-1]).GetLogger()
        self.__is_ui_ready = False
        self.__is_clear = False

        super(VisualizationConnection, self).__init__(parent)
        self.setupUi(self)

        self.buttonLoadResult.clicked.connect(self.LoadAll)
        self.buttonClearResult.clicked.connect(self.ClearAll)
        self.buttonSave.clicked.connect(self.Save)
        self.buttonGenerateDescription.clicked.connect(self.GenerateDescription)

        self.__plt_roc = self.canvasROC.getFigure().add_subplot(111)
        self.__plt_plot = self.canvasPlot.getFigure().add_subplot(111)
        self.__contribution = self.canvasFeature.getFigure().add_subplot(111)

        # Update Sheet
        self.tableClinicalStatistic.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableClinicalStatistic.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.comboSheet.currentIndexChanged.connect(self.UpdateSheet)
        self.checkMaxFeatureNumber.stateChanged.connect(self.UpdateSheet)
        self.tableClinicalStatistic.itemSelectionChanged.connect(self.ShowOneResult)

        # Update ROC canvas
        self.comboNormalizer.currentIndexChanged.connect(self.UpdateROC)
        self.comboDimensionReduction.currentIndexChanged.connect(self.UpdateROC)
        self.comboFeatureSelector.currentIndexChanged.connect(self.UpdateROC)
        self.comboClassifier.currentIndexChanged.connect(self.UpdateROC)
        self.spinBoxFeatureNumber.valueChanged.connect(self.UpdateROC)
        self.checkROCCVTrain.stateChanged.connect(self.UpdateROC)
        self.checkROCCVValidation.stateChanged.connect(self.UpdateROC)
        self.checkROCTrain.stateChanged.connect(self.UpdateROC)
        self.checkROCTest.stateChanged.connect(self.UpdateROC)

        # Update Plot canvas
        self.comboPlotX.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotY.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotNormalizer.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotDimensionReduction.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotFeatureSelector.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotClassifier.currentIndexChanged.connect(self.UpdatePlot)
        self.spinPlotFeatureNumber.valueChanged.connect(self.UpdatePlot)

        self.checkPlotCVTrain.stateChanged.connect(self.UpdatePlot)
        self.checkPlotCVValidation.stateChanged.connect(self.UpdatePlot)
        self.checkPlotTrain.stateChanged.connect(self.UpdatePlot)
        self.checkPlotOneSE.stateChanged.connect(self.UpdatePlot)
        self.checkPlotTest.stateChanged.connect(self.UpdatePlot)
       #

        # Update Contribution canvas
        self.radioContributionFeatureSelector.toggled.connect(self.UpdateContribution)
        self.radioContributionClassifier.toggled.connect(self.UpdateContribution)
        self.comboContributionNormalizor.currentIndexChanged.connect(self.UpdateContribution)
        self.comboContributionDimension.currentIndexChanged.connect(self.UpdateContribution)
        self.comboContributionFeatureSelector.currentIndexChanged.connect(self.UpdateContribution)
        self.comboContributionClassifier.currentIndexChanged.connect(self.UpdateContribution)
        self.spinContributeFeatureNumber.valueChanged.connect(self.UpdateContribution)

    def LoadAll(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            self._root_folder = dlg.selectedFiles()[0]

            if not os.path.exists(self._root_folder):
                return
            if not r'.FAEresult4129074093819729087' in os.listdir(self._root_folder):
                QMessageBox.about(self, 'Load Error', 'This folder is not supported for import')
                return

            try:
                self.lineEditResultPath.setText(self._root_folder)
                self._fae.LoadAll(self._root_folder)
                self.SetResultDescription()
                self.SetResultTable()
                self.InitialUi()
            except Exception as ex:
                QMessageBox.about(self, "Load Error", ex.__str__())
                self.logger.log('Load Error, The reason is ' + str(ex))
                self.ClearAll()
                return

            self.buttonClearResult.setEnabled(True)
            self.buttonSave.setEnabled(True)
            self.buttonLoadResult.setEnabled(False)

    def ClearAll(self):
        self.__is_clear = True
        self.buttonLoadResult.setEnabled(True)
        self.buttonSave.setEnabled(False)
        self.buttonClearResult.setEnabled(False)

        self.checkROCCVTrain.setChecked(False)
        self.checkROCCVValidation.setChecked(False)
        self.checkROCTrain.setChecked(False)
        self.checkROCTest.setChecked(False)
        self.checkPlotCVTrain.setChecked(False)
        self.checkPlotCVValidation.setChecked(False)
        self.checkPlotTrain.setChecked(False)
        self.checkPlotOneSE.setChecked(False)
        self.checkPlotTest.setChecked(False)
        self.radioContributionFeatureSelector.setChecked(False)
        self.checkMaxFeatureNumber.setChecked(False)
        self.canvasROC.getFigure().clear()
        self.canvasPlot.getFigure().clear()
        self.canvasFeature.getFigure().clear()
        self.__plt_roc = self.canvasROC.getFigure().add_subplot(111)
        self.__plt_plot = self.canvasPlot.getFigure().add_subplot(111)
        self.__contribution = self.canvasFeature.getFigure().add_subplot(111)
        self.canvasROC.draw()
        self.canvasPlot.draw()
        self.canvasFeature.draw()

        self.textEditDescription.clear()
        self.lineEditResultPath.clear()

        self.comboSheet.clear()
        self.comboClassifier.clear()
        self.comboDimensionReduction.clear()
        self.comboNormalizer.clear()
        self.comboFeatureSelector.clear()

        self.comboPlotClassifier.clear()
        self.comboPlotDimensionReduction.clear()
        self.comboPlotFeatureSelector.clear()
        self.comboPlotNormalizer.clear()
        self.comboPlotX.clear()
        self.comboPlotY.clear()

        self.comboContributionNormalizor.clear()
        self.comboContributionDimension.clear()
        self.comboContributionClassifier.clear()
        self.comboContributionFeatureSelector.clear()

        self.spinBoxFeatureNumber.setValue(0)
        self.spinPlotFeatureNumber.setValue(0)
        self.spinPlotFeatureNumber.setEnabled(False)
        self.spinContributeFeatureNumber.setValue(1)

        self.tableClinicalStatistic.clear()
        self.tableClinicalStatistic.setRowCount(0)
        self.tableClinicalStatistic.setColumnCount(0)
        self.tableClinicalStatistic.setHorizontalHeaderLabels(list([]))
        self.tableClinicalStatistic.setVerticalHeaderLabels(list([]))

        self._fae = FeatureAnalysisPipelines()
        self._root_folder = ''
        self.sheet_dict = dict()
        self.__is_ui_ready = False
        self.__is_clear = False

    def Save(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            store_folder = dlg.selectedFiles()[0]
            try:
                self.canvasROC.getFigure().savefig(os.path.join(store_folder, 'ROC.eps'), dpi=1200)
                self.canvasROC.getFigure().savefig(os.path.join(store_folder, 'ROC.jpg'), dpi=300)
            except Exception as e:
                QMessageBox.about(self, 'Save Figure Failed', 'There is no ROC figure.\n' + e.__str__())

            try:
                self.canvasPlot.getFigure().savefig(os.path.join(store_folder, 'Compare.eps'), dpi=1200)
                self.canvasPlot.getFigure().savefig(os.path.join(store_folder, 'Compare.jpg'), dpi=300)
            except Exception as e:
                QMessageBox.about(self, 'Save Figure Failed', 'There is no AUC comparison figure.\n' + e.__str__())

            try:
                self.canvasFeature.getFigure().savefig(os.path.join(store_folder, 'FeatureWeights.eps'), dpi=1200)
                self.canvasFeature.getFigure().savefig(os.path.join(store_folder, 'FeatureWeights.jpg'), dpi=300)
            except Exception as e:
                QMessageBox.about(self, 'Save Figure Failed', 'There is no Feature Contribution figure.\n' + e.__str__())

    def InitialUi(self):
        # Update ROC canvers
        for normalizer in self._fae.GetNormalizerList():
            self.comboNormalizer.addItem(normalizer.GetName())
        for dimension_reduction in self._fae.GetDimensionReductionList():
            self.comboDimensionReduction.addItem(dimension_reduction.GetName())
        for classifier in self._fae.GetClassifierList():
            self.comboClassifier.addItem(classifier.GetName())
        for feature_selector in self._fae.GetFeatureSelectorList():
            self.comboFeatureSelector.addItem(feature_selector.GetName())
        self.spinBoxFeatureNumber.setMinimum(int(self._fae.GetFeatureNumberList()[0]))
        self.spinBoxFeatureNumber.setMaximum(int(self._fae.GetFeatureNumberList()[-1]))

        # Update Plot canvars
        if len(self._fae.GetNormalizerList()) > 1:
            self.comboPlotX.addItem('Normaliaztion')
        if len(self._fae.GetDimensionReductionList()) > 1:
            self.comboPlotX.addItem('Dimension Reduction')
        if len(self._fae.GetFeatureSelectorList()) > 1:
            self.comboPlotX.addItem('Feature Selector')
        if len(self._fae.GetClassifierList()) > 1:
            self.comboPlotX.addItem('Classifier')
        if len(self._fae.GetFeatureNumberList()) > 1:
            self.comboPlotX.addItem('Feature Number')

        self.comboPlotY.addItem('AUC')

        for index in self._fae.GetNormalizerList():
            self.comboPlotNormalizer.addItem(index.GetName())
        for index in self._fae.GetDimensionReductionList():
            self.comboPlotDimensionReduction.addItem(index.GetName())
        for index in self._fae.GetFeatureSelectorList():
            self.comboPlotFeatureSelector.addItem(index.GetName())
        for index in self._fae.GetClassifierList():
            self.comboPlotClassifier.addItem(index.GetName())
        self.spinPlotFeatureNumber.setMinimum(int(self._fae.GetFeatureNumberList()[0]))
        self.spinPlotFeatureNumber.setMaximum(int(self._fae.GetFeatureNumberList()[-1]))

        # Update Contribution canvas
        for index in self._fae.GetNormalizerList():
            self.comboContributionNormalizor.addItem(index.GetName())
        for index in self._fae.GetDimensionReductionList():
            self.comboContributionDimension.addItem(index.GetName())
        for selector in self._fae.GetFeatureSelectorList():
            self.comboContributionFeatureSelector.addItem(selector.GetName())
        for classifier in self._fae.GetClassifierList():
            specific_name = classifier.GetName() + '_coef.csv'
            if self._SearchSpecificFile(int(self._fae.GetFeatureNumberList()[0]), specific_name):
                self.comboContributionClassifier.addItem(classifier.GetName())
        self.spinContributeFeatureNumber.setMinimum(int(self._fae.GetFeatureNumberList()[0]))
        self.spinContributeFeatureNumber.setMaximum(int(self._fae.GetFeatureNumberList()[-1]))

        self.__is_ui_ready = True

    def UpdateROC(self):
        if not self.__is_ui_ready:
            return
        if (self.comboNormalizer.count() == 0) or \
                (self.comboDimensionReduction.count() == 0) or \
                (self.comboFeatureSelector.count() == 0) or \
                (self.comboClassifier.count() == 0) or \
                (self.spinBoxFeatureNumber.value() == 0):
            return

        case_name = self.comboNormalizer.currentText() + '_' + \
                    self.comboDimensionReduction.currentText() + '_' + \
                    self.comboFeatureSelector.currentText() + '_' + \
                    str(self.spinBoxFeatureNumber.value()) + '_' + \
                    self.comboClassifier.currentText()

        case_folder = os.path.join(self._root_folder, case_name)

        pred_list, label_list, name_list = [], [], []
        if self.checkROCCVTrain.isChecked():
            train_pred = np.load(os.path.join(case_folder, 'train_predict.npy'))
            train_label = np.load(os.path.join(case_folder, 'train_label.npy'))
            pred_list.append(train_pred)
            label_list.append(train_label)
            name_list.append('CV Train')
        if self.checkROCCVValidation.isChecked():
            val_pred = np.load(os.path.join(case_folder, 'val_predict.npy'))
            val_label = np.load(os.path.join(case_folder, 'val_label.npy'))
            pred_list.append(val_pred)
            label_list.append(val_label)
            name_list.append('CV Validation')
        if self.checkROCTrain.isChecked():
            all_train_pred = np.load(os.path.join(case_folder, 'all_train_predict.npy'))
            all_train_label = np.load(os.path.join(case_folder, 'all_train_label.npy'))
            pred_list.append(all_train_pred)
            label_list.append(all_train_label)
            name_list.append('Train')
        if self.checkROCTest.isChecked():
            if os.path.exists(os.path.join(case_folder, 'test_label.npy')):
                test_pred = np.load(os.path.join(case_folder, 'test_predict.npy'))
                test_label = np.load(os.path.join(case_folder, 'test_label.npy'))
                pred_list.append(test_pred)
                label_list.append(test_label)
                name_list.append('Test')

        if len(pred_list) > 0:
            DrawROCList(pred_list, label_list, name_list=name_list, is_show=False, fig=self.canvasROC.getFigure())

        self.canvasROC.draw()

    def _UpdatePlotButtons(self, selected_index):
        index = [0, 0, 0, 0, 0]

        self.comboPlotNormalizer.setEnabled(True)
        self.comboPlotDimensionReduction.setEnabled(True)
        self.comboPlotFeatureSelector.setEnabled(True)
        self.comboPlotClassifier.setEnabled(True)
        self.spinPlotFeatureNumber.setEnabled(True)
        index[0] = self.comboPlotNormalizer.currentIndex()
        index[1] = self.comboPlotDimensionReduction.currentIndex()
        index[2] = self.comboPlotFeatureSelector.currentIndex()
        index[4] = self.comboPlotClassifier.currentIndex()
        index[3] = self.spinPlotFeatureNumber.value() - int(self._fae.GetFeatureNumberList()[0])

        if selected_index == 0:
            self.comboPlotNormalizer.setEnabled(False)
            index[0] = [temp for temp in range(len(self._fae.GetNormalizerList()))]
        elif selected_index == 1:
            self.comboPlotDimensionReduction.setEnabled(False)
            index[1] = [temp for temp in range(len(self._fae.GetDimensionReductionList()))]
        elif selected_index == 2:
            self.comboPlotFeatureSelector.setEnabled(False)
            index[2] = [temp for temp in range(len(self._fae.GetFeatureSelectorList()))]
        elif selected_index == 4:
            self.comboPlotClassifier.setEnabled(False)
            index[4] = [temp for temp in range(len(self._fae.GetClassifierList()))]
        elif selected_index == 3:
            self.spinPlotFeatureNumber.setEnabled(False)
            index[3] = [temp for temp in range(len(self._fae.GetFeatureNumberList()))]

        return index

    def UpdatePlot(self):
        if (not self.__is_ui_ready) or self.__is_clear:
            return

        if self.comboPlotX.count() == 0:
            return

        x_ticks = []
        x_label = ''
        selected_index = -1
        if self.comboPlotX.currentText() == 'Normaliaztion':
            selected_index = 0
            x_ticks = [instance.GetName() for instance in self._fae.GetNormalizerList()]
            x_label = 'Normalization Method'
        elif self.comboPlotX.currentText() == 'Dimension Reduction':
            selected_index = 1
            x_ticks = [instance.GetName() for instance in self._fae.GetDimensionReductionList()]
            x_label = 'Dimension Reduction Method'
        elif self.comboPlotX.currentText() == 'Feature Selector':
            selected_index = 2
            x_ticks = [instance.GetName() for instance in self._fae.GetFeatureSelectorList()]
            x_label = 'Feature Selecotr Method'
        elif self.comboPlotX.currentText() == 'Classifier':
            selected_index = 4
            x_ticks = [instance.GetName() for instance in self._fae.GetClassifierList()]
            x_label = 'Classifier Method'
        elif self.comboPlotX.currentText() == 'Feature Number':
            selected_index = 3
            x_ticks = list(map(int, self._fae.GetFeatureNumberList()))
            x_label = 'Feature Number'

        max_axis_list = [0, 1, 2, 3, 4]
        max_axis_list.remove(selected_index)
        max_axis = tuple(max_axis_list)

        index = self._UpdatePlotButtons(selected_index)

        show_data = []
        show_data_std =[]
        name_list = []

        if self.comboPlotY.currentText() == 'AUC':
            if self.checkPlotCVTrain.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['train'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['train'])
                show_data.append(temp[tuple(index)].tolist())
                show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('CV Train')
            if self.checkPlotCVValidation.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['val'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['val'])
                show_data.append(temp[tuple(index)].tolist())
                show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('CV Validation')
            if self.checkPlotTrain.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['all_train'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['all_train'])
                show_data.append(temp[tuple(index)].tolist())
                show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('Train')
            if self.checkPlotTest.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['test'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['test'])
                if temp.size > 0:
                    show_data.append(temp[tuple(index)].tolist())
                    show_data_std.append(auc_std[tuple(index)].tolist())
                    name_list.append('Test')


        if len(show_data) > 0:
            if selected_index == 3:
                DrawCurve(x_ticks, show_data, show_data_std, xlabel=x_label, ylabel=self.comboPlotY.currentText(),
                          name_list=name_list, is_show=False, one_se=self.checkPlotOneSE.isChecked(), fig=self.canvasPlot.getFigure())
            else:
                DrawBar(x_ticks, show_data, ylabel=self.comboPlotY.currentText(),
                          name_list=name_list, is_show=False, fig=self.canvasPlot.getFigure())

        self.canvasPlot.draw()

    def UpdateContribution(self):
        if (not self.__is_ui_ready) or self.__is_clear:
            return

        try:
            one_result_folder_name = self.comboContributionNormalizor.currentText() + '_' + \
                                self.comboContributionDimension.currentText() + '_' + \
                                self.comboContributionFeatureSelector.currentText() + '_' + \
                                str(self.spinContributeFeatureNumber.value()) + '_' + \
                                self.comboContributionClassifier.currentText()
            one_result_folder = os.path.join(self._root_folder, one_result_folder_name)
            # This is compatible with the previous version
            if not os.path.exists(one_result_folder):
                one_result_folder_name = self.comboContributionNormalizor.currentText() + '_Cos_' + \
                                         self.comboContributionFeatureSelector.currentText() + '_' + \
                                         str(self.spinContributeFeatureNumber.value()) + '_' + \
                                         self.comboContributionClassifier.currentText()
                one_result_folder = os.path.join(self._root_folder, one_result_folder_name)

            if self.radioContributionFeatureSelector.isChecked():
                file_name = self.comboContributionFeatureSelector.currentText() + '_sort.csv'
                file_path = os.path.join(one_result_folder, file_name)

                if not os.path.exists(file_path):
                    file_name = self.comboContributionFeatureSelector.currentText().lower() + '_sort.csv'
                    file_path = os.path.join(one_result_folder, file_name)

                if file_path:
                    df = pd.read_csv(file_path, index_col=0)
                    value = list(df.iloc[:, 0])

                    sort_by = df.columns.values[0]
                    if sort_by == 'rank':
                        reverse = False
                    elif sort_by == 'F' or sort_by == 'weight':
                        reverse = True
                    else:
                        reverse = False
                        print('Invalid feature selector sort name.')

                    #add positive and negatiove info for coef
                    processed_feature_name = list(df.index)
                    original_value = list(df.iloc[:, 0])
                    for index in range(len(original_value)):
                        if original_value[index] > 0:
                            processed_feature_name[index] = processed_feature_name[index] + ' P'
                        else:
                            processed_feature_name[index] = processed_feature_name[index] + ' N'

                    GeneralFeatureSort(processed_feature_name, value, max_num=self.spinContributeFeatureNumber.value(),
                                       is_show=False, fig=self.canvasFeature.getFigure(), reverse=reverse)

            elif self.radioContributionClassifier.isChecked():
                specific_name = self.comboContributionClassifier.currentText() + '_coef.csv'
                file_path = os.path.join(one_result_folder, specific_name)

                if not os.path.exists(file_path):
                    specific_name = self.comboContributionClassifier.currentText().lower() + '_coef.csv'
                    file_path = os.path.join(one_result_folder, specific_name)

                if file_path:
                    df = pd.read_csv(file_path, index_col=0)
                    feature_name = list(df.index)
                    value = list(np.abs(df.iloc[:, 0]))

                    #add positive and negatiove info for coef
                    processed_feature_name = list(df.index)
                    original_value = list(df.iloc[:, 0])
                    for index in range(len(original_value)):
                        if original_value[index] > 0:
                            processed_feature_name[index] = processed_feature_name[index] + ' P'
                        else:
                            processed_feature_name[index] = processed_feature_name[index] + ' N'

                    # try:
                    #     SortRadiomicsFeature(processed_feature_name, value, is_show=False, fig=self.canvasFeature.getFigure())
                    # except:
                    GeneralFeatureSort(processed_feature_name, value,
                                           is_show=False, fig=self.canvasFeature.getFigure())
            self.canvasFeature.draw()
        except Exception as e:
            content = 'In Visualization, UpdateContribution failed'
            self.logger.error('{}{}'.format(content, str(e)))
            QMessageBox.about(self, content, e.__str__())

    def SetResultDescription(self):
        text = "Normalizer:\n"
        for index in self._fae.GetNormalizerList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Dimension Reduction:\n"
        for index in self._fae.GetDimensionReductionList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Selector:\n"
        for index in self._fae.GetFeatureSelectorList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Number:\n"
        text += "{:s} - {:s}\n".format(self._fae.GetFeatureNumberList()[0], self._fae.GetFeatureNumberList()[-1])
        text += '\n'

        text += "Classifier:\n"
        for index in self._fae.GetClassifierList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += 'Cross Validation: ' + self._fae.GetCrossValidation().GetName()

        self.textEditDescription.setPlainText(text)

    def UpdateSheet(self):
        if self.__is_clear:
            self.comboSheet.setEnabled(False)
            return None


        if self.checkMaxFeatureNumber.isChecked():
            self.comboSheet.setEnabled(False)
        else:
            self.comboSheet.setEnabled(True)

        self.tableClinicalStatistic.clear()
        self.tableClinicalStatistic.setSortingEnabled(False)
        if self.comboSheet.currentText() == 'Train':
            df = self.sheet_dict['train']
        elif self.comboSheet.currentText() == 'Validation':
            df = self.sheet_dict['val']
        elif self.comboSheet.currentText() == 'Test':
            df = self.sheet_dict['test']
        else:
            return

        if self.checkMaxFeatureNumber.isChecked():
            self.sheet_dict['test'] = pd.read_csv(os.path.join(self._root_folder, 'test_result.csv'), index_col=0)
            data = self._fae.GetAUCMetric()['val']
            std_data = self._fae.GetAUCstdMetric()['val']
            df_val = self.sheet_dict['val']
            df_test = self.sheet_dict['test']
            name_list = []
            for normalizer_index, normalizer in enumerate(self._fae.GetNormalizerList()):
                for dimension_reducer_index, dimension_reducer in enumerate(self._fae.GetDimensionReductionList()):
                    for feature_selector_index, feature_selector in enumerate(self._fae.GetFeatureSelectorList()):
                        for classifier_index, classifier in enumerate(self._fae.GetClassifierList()):
                            sub_auc = data[normalizer_index, dimension_reducer_index, feature_selector_index, :,
                                      classifier_index]
                            sub_auc_std = std_data[normalizer_index, dimension_reducer_index, feature_selector_index, :,
                                      classifier_index]
                            one_se = max(sub_auc)-sub_auc_std[np.argmax(sub_auc)]
                            for feature_number_index in range(len(self._fae.GetFeatureNumberList())):
                                if data[normalizer_index, dimension_reducer_index,
                                        feature_selector_index, feature_number_index, classifier_index] >= one_se:
                                    name = normalizer.GetName() + '_' + dimension_reducer.GetName() + '_' + \
                                            feature_selector.GetName() + '_' + str(self._fae.GetFeatureNumberList()[feature_number_index]) + '_' + \
                                            classifier.GetName()
                                    name_list.append(name)
                                    break

            # choose the selected models from all test result
            df_val = df_val.loc[name_list]
            max_index = df_val['auc'].idxmax()
            sub_serise = df_val.loc[max_index]
            max_array = sub_serise.get_values().reshape(1, -1)
            max_auc_df = pd.DataFrame(data=max_array, columns=sub_serise.index.tolist(), index=[max_index])
            max_auc_95ci = max_auc_df.at[max_index, 'auc 95% CIs']

            max_auc_95ci = re.findall(r"\d+\.?\d*", max_auc_95ci)
            sub_val_df = df_val[(df_val['auc'] >= float(max_auc_95ci[0])) & (df_val['auc'] <= float(max_auc_95ci[1]))]

            index_by_val = sub_val_df.index.tolist()

            df = df_test.loc[index_by_val]

        df.sort_index(inplace=True)

        self.tableClinicalStatistic.setRowCount(df.shape[0])
        self.tableClinicalStatistic.setColumnCount(df.shape[1]+1)
        headerlabels = df.columns.tolist()
        headerlabels.insert(0, 'models name')
        self.tableClinicalStatistic.setHorizontalHeaderLabels(headerlabels)
        # self.tableClinicalStatistic.setVerticalHeaderLabels(list(df.index))

        for row_index in range(df.shape[0]):
            for col_index in range(df.shape[1]+1):
                if col_index == 0:
                    self.tableClinicalStatistic.setItem(row_index, col_index,
                                                        QTableWidgetItem(df.index[row_index]))
                else:
                    self.tableClinicalStatistic.setItem(row_index, col_index,
                                                        QTableWidgetItem(str(df.iloc[row_index, col_index-1])))

        self.tableClinicalStatistic.setSortingEnabled(True)

    def SetResultTable(self):
        self.sheet_dict['train'] = pd.read_csv(os.path.join(self._root_folder, 'train_result.csv'), index_col=0)
        self.comboSheet.addItem('Train')
        self.sheet_dict['val'] = pd.read_csv(os.path.join(self._root_folder, 'val_result.csv'), index_col=0)
        self.comboSheet.addItem('Validation')
        if os.path.exists(os.path.join(self._root_folder, 'test_result.csv')):
            self.sheet_dict['test'] = pd.read_csv(os.path.join(self._root_folder, 'test_result.csv'), index_col=0)
            self.comboSheet.addItem('Test')

        self.UpdateSheet()

    def _SearchSpecificFile(self, feature_number, specific_file_name, specific_file_name2=''):
        for rt, folder, files in os.walk(self._root_folder):
            for file_name in files:
                # print(file_name)
                if specific_file_name2:
                    if (file_name.lower() == specific_file_name.lower()) and \
                            ('_{:d}_'.format(feature_number) in rt) and \
                            (specific_file_name2 in rt):
                        return os.path.join(rt, file_name)
                else:
                    if (file_name.lower() == specific_file_name.lower()) and ('_{:d}_'.format(feature_number) in rt):
                        return os.path.join(rt, file_name)
        return ''

    def ShowOneResult(self):
        try:
            # for index in self.tableClinicalStatistic.selectedIndexes():
            if not self.tableClinicalStatistic.selectedIndexes():
                return None
            index = self.tableClinicalStatistic.selectedIndexes()[0]
            row = index.row()
            one_item = self.tableClinicalStatistic.item(row, 0)
            text = str(one_item.text())
            current_normalizer, current_dimension_reducer, current_feature_selector, current_feature_number, current_classifier = \
                text.split('_')

            self.comboNormalizer.setCurrentText(current_normalizer)
            self.comboDimensionReduction.setCurrentText(current_dimension_reducer)
            self.comboFeatureSelector.setCurrentText(current_feature_selector)
            self.comboClassifier.setCurrentText(current_classifier)
            self.spinBoxFeatureNumber.setValue(int(current_feature_number))
            if not (self.checkROCTrain.isChecked() or self.checkROCCVTrain.isChecked() or
                    self.checkROCCVValidation.isChecked() or self.checkROCTrain.isChecked()):
                self.checkROCCVTrain.setCheckState(True)
                self.checkROCCVValidation.setCheckState(True)
            self.UpdateROC()

            # Update the AUC versus feature number
            self.comboPlotNormalizer.setCurrentText(current_normalizer)
            self.comboPlotDimensionReduction.setCurrentText(current_dimension_reducer)
            self.comboPlotFeatureSelector.setCurrentText(current_feature_selector)
            self.comboPlotClassifier.setCurrentText(current_classifier)
            self.comboPlotX.setCurrentText('Feature Number')
            if not (self.checkPlotTrain.isChecked() or
                    self.checkPlotCVTrain.isChecked() or
                    self.checkPlotCVValidation.isChecked()):
                self.checkPlotCVValidation.setCheckState(True)
            self.UpdatePlot()


            # Update the Contribution
            self.comboContributionNormalizor.setCurrentText(current_normalizer)
            self.comboContributionDimension.setCurrentText(current_dimension_reducer)
            self.comboContributionFeatureSelector.setCurrentText(current_feature_selector)
            self.comboContributionClassifier.setCurrentText(current_classifier)
            self.spinContributeFeatureNumber.setValue(int(current_feature_number))
            self.UpdateContribution()

        except Exception as e:
            content = 'Visualization, ShowOneResult failed: '
            self.logger.error('{}{}'.format(content, str(e)))
            QMessageBox.about(self, content, e.__str__())

    def GenerateDescription(self):
        if (self.comboNormalizer.count() == 0) or \
                (self.comboDimensionReduction.count() == 0) or \
                (self.comboFeatureSelector.count() == 0) or \
                (self.comboClassifier.count() == 0) or \
                (self.spinBoxFeatureNumber.value() == 0):
            return

        case_name = self.comboNormalizer.currentText() + '_' + \
                    self.comboDimensionReduction.currentText() + '_' + \
                    self.comboFeatureSelector.currentText() + '_' + \
                    str(self.spinBoxFeatureNumber.value()) + '_' + \
                    self.comboClassifier.currentText()

        case_folder = os.path.join(self._root_folder, case_name)
        current_pipeline = OnePipeline()
        try:
            current_pipeline.LoadPipeline(os.path.join(case_folder, 'pipeline_info.csv'))
        except Exception as ex:
            QMessageBox.about(self, "In Description, Load Pipeline_info Error", ex.__str__())
            self.logger.error('Load Pipeline Error, The reason is ' + str(ex))

        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            store_folder = dlg.selectedFiles()[0]
            roc_path = os.path.join(store_folder, 'ROC.jpg')
            self.canvasROC.getFigure().savefig(roc_path, dpi=300)

            report = Description()
            try:
                report.Run(current_pipeline, self._root_folder, store_folder)
                os.system("explorer.exe {:s}".format(os.path.normpath(store_folder)))
            except Exception as ex:
                QMessageBox.about(self, 'Description Generate Error: ', ex.__str__())
                self.logger.log('Description Generate Error:  ' + str(ex))
Ejemplo n.º 2
0
class VisualizationConnection(QWidget, Ui_Visualization):
    def __init__(self, parent=None):
        self._root_folder = ''
        self._fae = FeatureAnalysisPipelines()
        self.sheet_dict = dict()

        super(VisualizationConnection, self).__init__(parent)
        self.setupUi(self)

        self.buttonLoadResult.clicked.connect(self.LoadAll)
        self.buttonClearResult.clicked.connect(self.ClearAll)
        self.buttonSave.clicked.connect(self.Save)

        self.__plt_roc = self.canvasROC.getFigure().add_subplot(111)
        self.__plt_plot = self.canvasPlot.getFigure().add_subplot(111)
        self.__contribution = self.canvasFeature.getFigure().add_subplot(111)

        # Update Sheet
        self.comboSheet.currentIndexChanged.connect(self.UpdateSheet)
        self.checkMaxFeatureNumber.stateChanged.connect(self.UpdateSheet)

        # Update ROC canvas
        self.comboNormalizer.currentIndexChanged.connect(self.UpdateROC)
        self.comboDimensionReduction.currentIndexChanged.connect(
            self.UpdateROC)
        self.comboFeatureSelector.currentIndexChanged.connect(self.UpdateROC)
        self.comboClassifier.currentIndexChanged.connect(self.UpdateROC)
        self.spinBoxFeatureNumber.valueChanged.connect(self.UpdateROC)
        self.checkROCCVTrain.stateChanged.connect(self.UpdateROC)
        self.checkROCCVValidation.stateChanged.connect(self.UpdateROC)
        self.checkROCTrain.stateChanged.connect(self.UpdateROC)
        self.checkROCTest.stateChanged.connect(self.UpdateROC)

        # Update Plot canvas
        self.comboPlotX.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotY.currentIndexChanged.connect(self.UpdatePlot)
        self.checkPlotMaximum.stateChanged.connect(self.UpdatePlot)
        self.comboPlotNormalizer.currentIndexChanged.connect(self.UpdatePlot)
        self.comboPlotDimensionReduction.currentIndexChanged.connect(
            self.UpdatePlot)
        self.comboPlotFeatureSelector.currentIndexChanged.connect(
            self.UpdatePlot)
        self.comboPlotClassifier.currentIndexChanged.connect(self.UpdatePlot)
        self.spinPlotFeatureNumber.valueChanged.connect(self.UpdatePlot)

        self.checkPlotCVTrain.stateChanged.connect(self.UpdatePlot)
        self.checkPlotCVValidation.stateChanged.connect(self.UpdatePlot)
        self.checkPlotTrain.stateChanged.connect(self.UpdatePlot)
        self.checkPlotTest.stateChanged.connect(self.UpdatePlot)

        # Update Contribution canvas
        self.checkContributionShow.stateChanged.connect(
            self.UpdateContribution)
        self.radioContributionFeatureSelector.toggled.connect(
            self.UpdateContribution)
        self.radioContributionClassifier.toggled.connect(
            self.UpdateContribution)
        self.comboContributionFeatureSelector.currentIndexChanged.connect(
            self.UpdateContribution)
        self.comboContributionClassifier.currentIndexChanged.connect(
            self.UpdateContribution)
        self.spinFeatureSelectorFeatureNumber.valueChanged.connect(
            self.UpdateContribution)
        self.spinClassifierFeatureNumber.valueChanged.connect(
            self.UpdateContribution)

    def LoadAll(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            self._root_folder = dlg.selectedFiles()[0]

            if not os.path.exists(self._root_folder):
                return
            if not r'.FAEresult4129074093819729087' in os.listdir(
                    self._root_folder):
                QMessageBox.about(self, 'Load Error',
                                  'This folder is not supported for import')
                return

            try:
                self.lineEditResultPath.setText(self._root_folder)
                self._fae.LoadAll(self._root_folder)
                self.SetResultDescription()
                self.SetResultTable()
                self.InitialUi()
            except Exception as ex:
                QMessageBox.about(self, "Load Error", ex.__str__())
                self.logger.log('Load Error, The reason is ' + str(ex))
                self.ClearAll()
                return

            self.buttonClearResult.setEnabled(True)
            self.buttonSave.setEnabled(True)
            self.buttonLoadResult.setEnabled(False)

    def ClearAll(self):

        self.buttonLoadResult.setEnabled(True)
        self.buttonSave.setEnabled(False)
        self.buttonClearResult.setEnabled(False)

        self.checkROCCVTrain.setChecked(False)
        self.checkROCCVValidation.setChecked(False)
        self.checkROCTrain.setChecked(False)
        self.checkROCTest.setChecked(False)
        self.checkPlotCVTrain.setChecked(False)
        self.checkPlotCVValidation.setChecked(False)
        self.checkPlotTrain.setChecked(False)
        self.checkPlotTest.setChecked(False)
        self.checkPlotMaximum.setChecked(False)
        self.checkContributionShow.setChecked(False)
        self.radioContributionFeatureSelector.setChecked(True)
        self.radioContributionFeatureSelector.setChecked(False)
        self.checkMaxFeatureNumber.setChecked(False)
        self.canvasROC.getFigure().clear()
        self.canvasPlot.getFigure().clear()
        self.canvasFeature.getFigure().clear()
        self.__plt_roc = self.canvasROC.getFigure().add_subplot(111)
        self.__plt_plot = self.canvasPlot.getFigure().add_subplot(111)
        self.__contribution = self.canvasFeature.getFigure().add_subplot(111)
        self.canvasROC.draw()
        self.canvasPlot.draw()
        self.canvasFeature.draw()

        self.textEditDescription.clear()
        self.lineEditResultPath.clear()

        self.comboSheet.clear()
        self.comboClassifier.clear()
        self.comboDimensionReduction.clear()
        self.comboNormalizer.clear()
        self.comboFeatureSelector.clear()

        self.comboPlotClassifier.clear()
        self.comboPlotDimensionReduction.clear()
        self.comboPlotFeatureSelector.clear()
        self.comboPlotNormalizer.clear()
        self.comboPlotX.clear()
        self.comboPlotY.clear()

        self.comboContributionClassifier.clear()
        self.comboContributionFeatureSelector.clear()

        self.spinBoxFeatureNumber.setValue(0)
        self.spinPlotFeatureNumber.setValue(0)
        self.spinPlotFeatureNumber.setEnabled(False)
        self.spinFeatureSelectorFeatureNumber.setValue(1)
        self.spinClassifierFeatureNumber.setValue(1)

        self.tableClinicalStatistic.clear()

        self.tableClinicalStatistic.setRowCount(0)
        self.tableClinicalStatistic.setColumnCount(0)
        self.tableClinicalStatistic.setHorizontalHeaderLabels(list([]))
        self.tableClinicalStatistic.setVerticalHeaderLabels(list([]))

        self._fae = FeatureAnalysisPipelines()
        self._root_folder = ''
        self.sheet_dict = dict()

    def Save(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            store_folder = dlg.selectedFiles()[0]
            self.canvasROC.getFigure().savefig(os.path.join(
                store_folder, 'ROC.eps'),
                                               dpi=1200)
            self.canvasROC.getFigure().savefig(os.path.join(
                store_folder, 'ROC.jpg'),
                                               dpi=300)
            self.canvasPlot.getFigure().savefig(os.path.join(
                store_folder, 'Compare.eps'),
                                                dpi=1200)
            self.canvasPlot.getFigure().savefig(os.path.join(
                store_folder, 'Compare.jpg'),
                                                dpi=300)
            self.canvasFeature.getFigure().savefig(os.path.join(
                store_folder, 'FeatureWeights.eps'),
                                                   dpi=1200)
            self.canvasFeature.getFigure().savefig(os.path.join(
                store_folder, 'FeatureWeights.jpg'),
                                                   dpi=300)

    def InitialUi(self):
        # Update ROC canvers
        for normalizer in self._fae.GetNormalizerList():
            self.comboNormalizer.addItem(normalizer.GetName())
        for dimension_reduction in self._fae.GetDimensionReductionList():
            self.comboDimensionReduction.addItem(dimension_reduction.GetName())
        for classifier in self._fae.GetClassifierList():
            self.comboClassifier.addItem(classifier.GetName())
        for feature_selector in self._fae.GetFeatureSelectorList():
            self.comboFeatureSelector.addItem(feature_selector.GetName())
        self.spinBoxFeatureNumber.setMinimum(
            int(self._fae.GetFeatureNumberList()[0]))
        self.spinBoxFeatureNumber.setMaximum(
            int(self._fae.GetFeatureNumberList()[-1]))

        # Update Plot canvars
        if len(self._fae.GetNormalizerList()) > 1:
            self.comboPlotX.addItem('Normaliaztion')
        if len(self._fae.GetDimensionReductionList()) > 1:
            self.comboPlotX.addItem('Dimension Reduction')
        if len(self._fae.GetFeatureSelectorList()) > 1:
            self.comboPlotX.addItem('Feature Selector')
        if len(self._fae.GetClassifierList()) > 1:
            self.comboPlotX.addItem('Classifier')
        if len(self._fae.GetFeatureNumberList()) > 1:
            self.comboPlotX.addItem('Feature Number')

        self.comboPlotY.addItem('AUC')

        for index in self._fae.GetNormalizerList():
            self.comboPlotNormalizer.addItem(index.GetName())
        for index in self._fae.GetDimensionReductionList():
            self.comboPlotDimensionReduction.addItem(index.GetName())
        for index in self._fae.GetFeatureSelectorList():
            self.comboPlotFeatureSelector.addItem(index.GetName())
        for index in self._fae.GetClassifierList():
            self.comboPlotClassifier.addItem(index.GetName())
        self.spinPlotFeatureNumber.setMinimum(
            int(self._fae.GetFeatureNumberList()[0]))
        self.spinPlotFeatureNumber.setMaximum(
            int(self._fae.GetFeatureNumberList()[-1]))

        # Update Contribution canvas
        # self.spinFeatureSelectorFeatureNumber.setMaximum(int(self._fae.GetFeatureNumberList()[-1]))
        self.spinClassifierFeatureNumber.setMinimum(
            int(self._fae.GetFeatureNumberList()[0]))
        self.spinClassifierFeatureNumber.setMaximum(
            int(self._fae.GetFeatureNumberList()[-1]))
        for selector in self._fae.GetFeatureSelectorList():
            self.comboContributionFeatureSelector.addItem(selector.GetName())
        for classifier in self._fae.GetClassifierList():
            specific_name = classifier.GetName() + '_coef.csv'
            if self._SearchSpecificFile(
                    int(self._fae.GetFeatureNumberList()[0]), specific_name):
                self.comboContributionClassifier.addItem(classifier.GetName())

    def UpdateROC(self):
        if (self.comboNormalizer.count() == 0) or \
                (self.comboDimensionReduction.count() == 0) or \
                (self.comboFeatureSelector.count() == 0) or \
                (self.comboClassifier.count() == 0) or \
                (self.spinBoxFeatureNumber.value() == 0):
            return

        case_name = self.comboNormalizer.currentText() + '_' + \
                    self.comboDimensionReduction.currentText() + '_' + \
                    self.comboFeatureSelector.currentText() + '_' + \
                    str(self.spinBoxFeatureNumber.value()) + '_' + \
                    self.comboClassifier.currentText()

        case_folder = os.path.join(self._root_folder, case_name)

        pred_list, label_list, name_list = [], [], []
        if self.checkROCCVTrain.isChecked():
            train_pred = np.load(os.path.join(case_folder,
                                              'train_predict.npy'))
            train_label = np.load(os.path.join(case_folder, 'train_label.npy'))
            pred_list.append(train_pred)
            label_list.append(train_label)
            name_list.append('CV Train')
        if self.checkROCCVValidation.isChecked():
            val_pred = np.load(os.path.join(case_folder, 'val_predict.npy'))
            val_label = np.load(os.path.join(case_folder, 'val_label.npy'))
            pred_list.append(val_pred)
            label_list.append(val_label)
            name_list.append('CV Validation')
        if self.checkROCTrain.isChecked():
            all_train_pred = np.load(
                os.path.join(case_folder, 'all_train_predict.npy'))
            all_train_label = np.load(
                os.path.join(case_folder, 'all_train_label.npy'))
            pred_list.append(all_train_pred)
            label_list.append(all_train_label)
            name_list.append('Train')
        if self.checkROCTest.isChecked():
            if os.path.exists(os.path.join(case_folder, 'test_label.npy')):
                test_pred = np.load(
                    os.path.join(case_folder, 'test_predict.npy'))
                test_label = np.load(
                    os.path.join(case_folder, 'test_label.npy'))
                pred_list.append(test_pred)
                label_list.append(test_label)
                name_list.append('Test')

        if len(pred_list) > 0:
            DrawROCList(pred_list,
                        label_list,
                        name_list=name_list,
                        is_show=False,
                        fig=self.canvasROC.getFigure())

        self.canvasROC.draw()

    def _UpdatePlotButtons(self, selected_index):
        index = [0, 0, 0, 0, 0]
        if self.checkPlotMaximum.isChecked():
            self.comboPlotNormalizer.setEnabled(False)
            self.comboPlotDimensionReduction.setEnabled(False)
            self.comboPlotFeatureSelector.setEnabled(False)
            self.comboPlotClassifier.setEnabled(False)
            self.spinPlotFeatureNumber.setEnabled(False)
        else:
            self.comboPlotNormalizer.setEnabled(True)
            self.comboPlotDimensionReduction.setEnabled(True)
            self.comboPlotFeatureSelector.setEnabled(True)
            self.comboPlotClassifier.setEnabled(True)
            self.spinPlotFeatureNumber.setEnabled(True)
            index[0] = self.comboPlotNormalizer.currentIndex()
            index[1] = self.comboPlotDimensionReduction.currentIndex()
            index[2] = self.comboPlotFeatureSelector.currentIndex()
            index[4] = self.comboPlotClassifier.currentIndex()
            index[3] = self.spinPlotFeatureNumber.value() - int(
                self._fae.GetFeatureNumberList()[0])

            if selected_index == 0:
                self.comboPlotNormalizer.setEnabled(False)
                index[0] = [
                    temp for temp in range(len(self._fae.GetNormalizerList()))
                ]
            elif selected_index == 1:
                self.comboPlotDimensionReduction.setEnabled(False)
                index[1] = [
                    temp for temp in range(
                        len(self._fae.GetDimensionReductionList()))
                ]
            elif selected_index == 2:
                self.comboPlotFeatureSelector.setEnabled(False)
                index[2] = [
                    temp
                    for temp in range(len(self._fae.GetFeatureSelectorList()))
                ]
            elif selected_index == 4:
                self.comboPlotClassifier.setEnabled(False)
                index[4] = [
                    temp for temp in range(len(self._fae.GetClassifierList()))
                ]
            elif selected_index == 3:
                self.spinPlotFeatureNumber.setEnabled(False)
                index[3] = [
                    temp
                    for temp in range(len(self._fae.GetFeatureNumberList()))
                ]

        return index

    def UpdatePlot(self):
        if self.comboPlotX.count() == 0:
            return

        x_ticks = []
        x_label = ''
        selected_index = -1
        if self.comboPlotX.currentText() == 'Normaliaztion':
            selected_index = 0
            x_ticks = [
                instance.GetName()
                for instance in self._fae.GetNormalizerList()
            ]
            x_label = 'Normalization Method'
        elif self.comboPlotX.currentText() == 'Dimension Reduction':
            selected_index = 1
            x_ticks = [
                instance.GetName()
                for instance in self._fae.GetDimensionReductionList()
            ]
            x_label = 'Dimension Reduction Method'
        elif self.comboPlotX.currentText() == 'Feature Selector':
            selected_index = 2
            x_ticks = [
                instance.GetName()
                for instance in self._fae.GetFeatureSelectorList()
            ]
            x_label = 'Feature Selecotr Method'
        elif self.comboPlotX.currentText() == 'Classifier':
            selected_index = 4
            x_ticks = [
                instance.GetName()
                for instance in self._fae.GetClassifierList()
            ]
            x_label = 'Classifier Method'
        elif self.comboPlotX.currentText() == 'Feature Number':
            selected_index = 3
            x_ticks = list(map(int, self._fae.GetFeatureNumberList()))
            x_label = 'Feature Number'

        max_axis_list = [0, 1, 2, 3, 4]
        max_axis_list.remove(selected_index)
        max_axis = tuple(max_axis_list)

        index = self._UpdatePlotButtons(selected_index)

        show_data = []
        show_data_std = []
        name_list = []

        if self.comboPlotY.currentText() == 'AUC':
            if self.checkPlotCVTrain.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['train'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['train'])
                if self.checkPlotMaximum.isChecked():
                    show_data.append(np.max(temp, axis=max_axis).tolist())
                else:
                    show_data.append(temp[tuple(index)].tolist())
                    show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('CV Train')
            if self.checkPlotCVValidation.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['val'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['val'])
                if self.checkPlotMaximum.isChecked():
                    show_data.append(np.max(temp, axis=max_axis).tolist())
                else:
                    show_data.append(temp[tuple(index)].tolist())
                    show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('CV Validation')
            if self.checkPlotTrain.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['all_train'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['all_train'])
                if self.checkPlotMaximum.isChecked():
                    show_data.append(np.max(temp, axis=max_axis).tolist())
                else:
                    show_data.append(temp[tuple(index)].tolist())
                    show_data_std.append(auc_std[tuple(index)].tolist())
                name_list.append('Train')
            if self.checkPlotTest.isChecked():
                temp = deepcopy(self._fae.GetAUCMetric()['test'])
                auc_std = deepcopy(self._fae.GetAUCstdMetric()['test'])
                if temp.size > 0:
                    if self.checkPlotMaximum.isChecked():
                        show_data.append(np.max(temp, axis=max_axis).tolist())
                    else:
                        show_data.append(temp[tuple(index)].tolist())
                        show_data_std.append(auc_std[tuple(index)].tolist())
                    name_list.append('Test')

        if len(show_data) > 0:
            if selected_index == 3:
                DrawCurve(x_ticks,
                          show_data,
                          show_data_std,
                          xlabel=x_label,
                          ylabel=self.comboPlotY.currentText(),
                          name_list=name_list,
                          is_show=False,
                          fig=self.canvasPlot.getFigure())
            else:
                DrawBar(x_ticks,
                        show_data,
                        ylabel=self.comboPlotY.currentText(),
                        name_list=name_list,
                        is_show=False,
                        fig=self.canvasPlot.getFigure())

        self.canvasPlot.draw()

    def UpdateContribution(self):
        if not self.checkContributionShow.isChecked():
            return

        if self.radioContributionFeatureSelector.isChecked():
            file_name = self.comboContributionFeatureSelector.currentText(
            ) + '_sort.csv'
            file_path = self._SearchSpecificFile(
                int(self._fae.GetFeatureNumberList()[0]), file_name)
            if file_path:
                df = pd.read_csv(file_path, index_col=0)

                feature_name = list(df.index)
                value = list(np.abs(df.iloc[:, 0]))

                GeneralFeatureSort(
                    feature_name,
                    value,
                    max_num=self.spinFeatureSelectorFeatureNumber.value(),
                    is_show=False,
                    fig=self.canvasFeature.getFigure())
        elif self.radioContributionClassifier.isChecked():
            specific_name = self.comboContributionClassifier.currentText(
            ) + '_coef.csv'
            feature_selector_name = self.comboContributionFeatureSelector.currentText(
            )
            file_path = self._SearchSpecificFile(
                self.spinClassifierFeatureNumber.value(), specific_name,
                feature_selector_name)
            if file_path:
                df = pd.read_csv(file_path, index_col=0)
                feature_name = list(df.index)
                value = list(np.abs(df.iloc[:, 0]))
                try:
                    SortRadiomicsFeature(feature_name,
                                         value,
                                         is_show=False,
                                         fig=self.canvasFeature.getFigure())
                except:
                    GeneralFeatureSort(feature_name,
                                       value,
                                       is_show=False,
                                       fig=self.canvasFeature.getFigure())

        self.canvasFeature.draw()

    def SetResultDescription(self):
        text = "Normalizer:\n"
        for index in self._fae.GetNormalizerList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Dimension Reduction:\n"
        for index in self._fae.GetDimensionReductionList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Selector:\n"
        for index in self._fae.GetFeatureSelectorList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Number:\n"
        text += "{:s} - {:s}\n".format(self._fae.GetFeatureNumberList()[0],
                                       self._fae.GetFeatureNumberList()[-1])
        text += '\n'

        text += "Classifier:\n"
        for index in self._fae.GetClassifierList():
            text += (index.GetName() + '\n')
        text += '\n'

        self.textEditDescription.setPlainText(text)

    def UpdateSheet(self):
        data = np.array([])
        df = pd.DataFrame()
        data = self._fae.GetAUCMetric()
        std_data = self._fae.GetAUCstdMetric()
        self.tableClinicalStatistic.clear()
        self.tableClinicalStatistic.setSortingEnabled(False)
        if self.comboSheet.currentText() == 'Train':
            data = self._fae.GetAUCMetric()['train']
            std_data = self._fae.GetAUCstdMetric()['train']
            df = self.sheet_dict['train']
        elif self.comboSheet.currentText() == 'Validation':
            data = self._fae.GetAUCMetric()['val']
            std_data = self._fae.GetAUCstdMetric()['val']
            df = self.sheet_dict['val']
        elif self.comboSheet.currentText() == 'Test':
            data = self._fae.GetAUCMetric()['test']
            std_data = self._fae.GetAUCstdMetric()['test']
            df = self.sheet_dict['test']
        elif self.comboSheet.currentText() == 'Test On Val':
            data = self._fae.GetAUCMetric()['val']
            std_data = self._fae.GetAUCstdMetric()['val']
            df = self.sheet_dict['test']

        else:
            return

        if self.checkMaxFeatureNumber.isChecked():
            name_list = []
            for normalizer, normalizer_index in zip(
                    self._fae.GetNormalizerList(),
                    range(len(self._fae.GetNormalizerList()))):
                for dimension_reducer, dimension_reducer_index in zip(
                        self._fae.GetDimensionReductionList(),
                        range(len(self._fae.GetDimensionReductionList()))):
                    for feature_selector, feature_selector_index in zip(
                            self._fae.GetFeatureSelectorList(),
                            range(len(self._fae.GetFeatureSelectorList()))):
                        for classifier, classifier_index in zip(
                                self._fae.GetClassifierList(),
                                range(len(self._fae.GetClassifierList()))):
                            sub_auc = data[normalizer_index,
                                           dimension_reducer_index,
                                           feature_selector_index, :,
                                           classifier_index]
                            sub_auc_std = std_data[normalizer_index,
                                                   dimension_reducer_index,
                                                   feature_selector_index, :,
                                                   classifier_index]
                            one_se = max(sub_auc) - sub_auc_std[np.argmax(
                                sub_auc)]
                            for feature_number_index in range(
                                    len(self._fae.GetFeatureNumberList())):
                                if data[normalizer_index,
                                        dimension_reducer_index,
                                        feature_selector_index,
                                        feature_number_index,
                                        classifier_index] >= one_se:
                                    name = normalizer.GetName() + '_' + dimension_reducer.GetName() + '_' + \
                                    feature_selector.GetName() + '_' + str(self._fae.GetFeatureNumberList()[feature_number_index]) + '_' + \
                                    classifier.GetName()
                                    name_list.append(name)
                                    break

            df = df.loc[name_list]
        df.sort_index(inplace=True)

        self.tableClinicalStatistic.setRowCount(df.shape[0])
        self.tableClinicalStatistic.setColumnCount(df.shape[1] + 1)
        headerlabels = df.columns.tolist()
        headerlabels.insert(0, 'models name')
        self.tableClinicalStatistic.setHorizontalHeaderLabels(headerlabels)
        # self.tableClinicalStatistic.setVerticalHeaderLabels(list(df.index))

        for row_index in range(df.shape[0]):
            for col_index in range(df.shape[1] + 1):
                if col_index == 0:
                    self.tableClinicalStatistic.setItem(
                        row_index, col_index,
                        QTableWidgetItem(df.index[row_index]))
                else:
                    self.tableClinicalStatistic.setItem(
                        row_index, col_index,
                        QTableWidgetItem(str(df.iloc[row_index,
                                                     col_index - 1])))

        self.tableClinicalStatistic.setSortingEnabled(True)

    def SetResultTable(self):
        self.sheet_dict['train'] = pd.read_csv(os.path.join(
            self._root_folder, 'train_result.csv'),
                                               index_col=0)
        self.comboSheet.addItem('Train')
        self.sheet_dict['val'] = pd.read_csv(os.path.join(
            self._root_folder, 'val_result.csv'),
                                             index_col=0)
        self.comboSheet.addItem('Validation')
        if os.path.exists(os.path.join(self._root_folder, 'test_result.csv')):
            self.sheet_dict['test'] = pd.read_csv(os.path.join(
                self._root_folder, 'test_result.csv'),
                                                  index_col=0)
            self.comboSheet.addItem('Test')
            self.comboSheet.addItem('Test On Val')

        self.UpdateSheet()

    def _SearchSpecificFile(self,
                            feature_number,
                            specific_file_name,
                            specific_file_name2=''):
        for rt, folder, files in os.walk(self._root_folder):
            for file_name in files:
                # print(file_name)
                if specific_file_name2:
                    if (file_name.lower() == specific_file_name.lower()) and \
                            ('_{:d}_'.format(feature_number) in rt) and \
                            (specific_file_name2 in rt):
                        return os.path.join(rt, file_name)
                else:
                    if (file_name.lower() == specific_file_name.lower()) and (
                            '_{:d}_'.format(feature_number) in rt):
                        return os.path.join(rt, file_name)

        return ''
Ejemplo n.º 3
0
class ReportConnection(QWidget, Ui_Report):
    def __init__(self, parent=None):
        self._root_folder = ''
        self._fae = FeatureAnalysisPipelines()
        self._training_data_container = DataContainer()
        self._testing_data_container = DataContainer()
        self._current_pipeline = OnePipeline()

        super(ReportConnection, self).__init__(parent)
        self.setupUi(self)

        self.buttonLoadTrainingData.clicked.connect(self.LoadTrainingData)
        self.buttonClearTrainingData.clicked.connect(self.ClearTrainingData)
        self.buttonLoadTestingData.clicked.connect(self.LoadTestingData)
        self.buttonClearTestingData.clicked.connect(self.ClearTestingData)

        self.buttonLoadResult.clicked.connect(self.LoadAll)
        self.buttonClearResult.clicked.connect(self.ClearAll)

        self.buttonGenerate.clicked.connect(self.Generate)

        self.__plt_roc = self.canvasROC.getFigure().add_subplot(111)

        # Update ROC canvas
        self.comboNormalizer.currentIndexChanged.connect(self.UpdateROC)
        self.comboDimensionReduction.currentIndexChanged.connect(
            self.UpdateROC)
        self.comboFeatureSelector.currentIndexChanged.connect(self.UpdateROC)
        self.comboClassifier.currentIndexChanged.connect(self.UpdateROC)
        self.spinBoxFeatureNumber.valueChanged.connect(self.UpdateROC)
        self.checkROCTrain.stateChanged.connect(self.UpdateROC)
        self.checkROCValidation.stateChanged.connect(self.UpdateROC)
        self.checkROCTest.stateChanged.connect(self.UpdateROC)

        self.SetPipelineStateButton(False)

    def Generate(self):
        if self._training_data_container.IsEmpty():
            QMessageBox.about(self, '', 'Load training data at least')
            return

        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            store_folder = dlg.selectedFiles()[0]
            roc_path = os.path.join(store_folder, 'ROC.jpg')
            self.canvasROC.getFigure().savefig(roc_path, dpi=300)

            report = Report()
            try:
                report.Run(self._training_data_container,
                           self._current_pipeline, self._root_folder,
                           store_folder, self._testing_data_container)
                os.system("explorer.exe {:s}".format(
                    os.path.normpath(store_folder)))
            except Exception as ex:
                QMessageBox.about(self, 'Report Generate Error: ',
                                  ex.__str__())

    def LoadTrainingData(self):
        dlg = QFileDialog()
        file_name, _ = dlg.getOpenFileName(self,
                                           'Open SCV file',
                                           directory=r'C:\MyCode\FAE\Example',
                                           filter="csv files (*.csv)")
        try:
            self._training_data_container.Load(file_name)
            # self.SetStateButtonBeforeLoading(True)
            self.lineEditTrainingData.setText(file_name)
            self.UpdateDataDescription()
        except Exception as ex:
            QMessageBox.about(self, "Load Error", ex.__str__())

    def ClearTrainingData(self):
        self._training_data_container = DataContainer()
        # self.SetStateButtonBeforeLoading(False)
        self.lineEditTrainingData.setText("")
        self.UpdateDataDescription()

    def LoadTestingData(self):
        dlg = QFileDialog()
        file_name, _ = dlg.getOpenFileName(self,
                                           'Open SCV file',
                                           filter="csv files (*.csv)")
        try:
            self._testing_data_container.Load(file_name)
            self.lineEditTestingData.setText(file_name)
            self.UpdateDataDescription()
        except Exception as ex:
            QMessageBox.about(self, "Load Error", ex.__str__())

    def ClearTestingData(self):
        self._testing_data_container = DataContainer()
        self.lineEditTestingData.setText("")
        self.UpdateDataDescription()

    def UpdateDataDescription(self):
        show_text = ''
        if not self._training_data_container.IsEmpty():
            show_text += "The number of training cases: {:d}\n".format(
                len(self._training_data_container.GetCaseName()))
            show_text += "The number of training features: {:d}\n".format(
                len(self._training_data_container.GetFeatureName()))
            if len(np.unique(self._training_data_container.GetLabel())) == 2:
                positive_number = len(
                    np.where(self._training_data_container.GetLabel() == np.
                             max(self._training_data_container.GetLabel()))[0])
                negative_number = len(
                    self._training_data_container.GetLabel()) - positive_number
                assert (positive_number + negative_number == len(
                    self._training_data_container.GetLabel()))
                show_text += "The number of training positive samples: {:d}\n".format(
                    positive_number)
                show_text += "The number of training negative samples: {:d}\n".format(
                    negative_number)

        show_text += '\n'
        if not self._testing_data_container.IsEmpty():
            show_text += "The number of testing cases: {:d}\n".format(
                len(self._testing_data_container.GetCaseName()))
            show_text += "The number of testing features: {:d}\n".format(
                len(self._testing_data_container.GetFeatureName()))
            if len(np.unique(self._testing_data_container.GetLabel())) == 2:
                positive_number = len(
                    np.where(self._testing_data_container.GetLabel() == np.max(
                        self._testing_data_container.GetLabel()))[0])
                negative_number = len(
                    self._testing_data_container.GetLabel()) - positive_number
                assert (positive_number + negative_number == len(
                    self._testing_data_container.GetLabel()))
                show_text += "The number of testing positive samples: {:d}\n".format(
                    positive_number)
                show_text += "The number of testing negative samples: {:d}\n".format(
                    negative_number)

        self.textEditDataDescription.setText(show_text)

    def LoadAll(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.DirectoryOnly)
        dlg.setOption(QFileDialog.ShowDirsOnly)

        if dlg.exec_():
            self._root_folder = dlg.selectedFiles()[0]

            if not os.path.exists(self._root_folder):
                return
            if not r'.FAEresult4129074093819729087' in os.listdir(
                    self._root_folder):
                QMessageBox.about(self, 'Load Error',
                                  'This folder is not supported for import')
                return
            try:
                self.lineEditResultPath.setText(self._root_folder)
                self._fae.LoadAll(self._root_folder)
                self.SetResultDescription()
                self.InitialUi()
            except Exception as ex:
                QMessageBox.about(self, "Load Error", ex.__str__())
                self.ClearAll()
                return

            self.SetPipelineStateButton(True)

    def ClearAll(self):
        self.buttonLoadResult.setEnabled(True)
        self.buttonClearResult.setEnabled(False)

        self._fae = FeatureAnalysisPipelines()
        self.textEditDescription.setPlainText('')
        self.lineEditResultPath.setText('')
        self.InitialUi()

        self.checkROCTrain.setChecked(False)
        self.checkROCValidation.setChecked(False)
        self.checkROCTest.setChecked(False)

        self.spinBoxFeatureNumber.setValue(1)

        self.canvasROC.getFigure().clear()
        self.canvasROC.draw()

        self.SetPipelineStateButton(False)

    def SetPipelineStateButton(self, state):
        self.checkROCTrain.setEnabled(state)
        self.checkROCValidation.setEnabled(state)
        self.checkROCTest.setEnabled(state)

        self.comboNormalizer.setEnabled(state)
        self.comboDimensionReduction.setEnabled(state)
        self.comboFeatureSelector.setEnabled(state)
        self.comboClassifier.setEnabled(state)
        self.spinBoxFeatureNumber.setEnabled(state)

        self.buttonClearResult.setEnabled(state)
        self.buttonLoadResult.setEnabled(not state)

        self.buttonGenerate.setEnabled(state)

    def InitialUi(self):
        # Update ROC canvers
        self.comboNormalizer.clear()
        for normalizer in self._fae.GetNormalizerList():
            self.comboNormalizer.addItem(normalizer.GetName())
        self.comboDimensionReduction.clear()
        for dimension_reduction in self._fae.GetDimensionReductionList():
            self.comboDimensionReduction.addItem(dimension_reduction.GetName())
        self.comboClassifier.clear()
        for classifier in self._fae.GetClassifierList():
            self.comboClassifier.addItem(classifier.GetName())
        self.comboFeatureSelector.clear()
        for feature_selector in self._fae.GetFeatureSelectorList():
            self.comboFeatureSelector.addItem(feature_selector.GetName())

        if self._fae.GetFeatureNumberList() != []:
            self.spinBoxFeatureNumber.setMinimum(
                int(self._fae.GetFeatureNumberList()[0]))
            self.spinBoxFeatureNumber.setMaximum(
                int(self._fae.GetFeatureNumberList()[-1]))

    def SetResultDescription(self):
        text = "Normalizer:\n"
        for index in self._fae.GetNormalizerList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Dimension Reduction:\n"
        for index in self._fae.GetDimensionReductionList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Selector:\n"
        for index in self._fae.GetFeatureSelectorList():
            text += (index.GetName() + '\n')
        text += '\n'

        text += "Feature Number:\n"
        text += "{:s} - {:s}\n".format(self._fae.GetFeatureNumberList()[0],
                                       self._fae.GetFeatureNumberList()[-1])
        text += '\n'

        text += "Classifier:\n"
        for index in self._fae.GetClassifierList():
            text += (index.GetName() + '\n')
        text += '\n'

        self.textEditDescription.setPlainText(text)

    def UpdateROC(self):
        if (self.comboNormalizer.count() == 0) or \
                (self.comboDimensionReduction.count() == 0) or \
                (self.comboFeatureSelector.count() == 0) or \
                (self.comboClassifier.count() == 0) or \
                (self.spinBoxFeatureNumber.value() == 0):
            return

        case_name = self.comboNormalizer.currentText() + '_' + \
                    self.comboDimensionReduction.currentText() + '_' + \
                    self.comboFeatureSelector.currentText() + '_' + \
                    str(self.spinBoxFeatureNumber.value()) + '_' + \
                    self.comboClassifier.currentText()

        case_folder = os.path.join(self._root_folder, case_name)
        try:
            self._current_pipeline.LoadPipeline(
                os.path.join(case_folder, 'pipeline_info.csv'))
        except Exception as ex:
            QMessageBox.about(self, "Load Error", ex.__str__())

        pred_list, label_list, name_list = [], [], []
        if self.checkROCTrain.isChecked():
            train_pred = np.load(os.path.join(case_folder,
                                              'train_predict.npy'))
            train_label = np.load(os.path.join(case_folder, 'train_label.npy'))
            pred_list.append(train_pred)
            label_list.append(train_label)
            name_list.append('train')
        if self.checkROCValidation.isChecked():
            val_pred = np.load(os.path.join(case_folder, 'val_predict.npy'))
            val_label = np.load(os.path.join(case_folder, 'val_label.npy'))
            pred_list.append(val_pred)
            label_list.append(val_label)
            name_list.append('validation')
        if self.checkROCTest.isChecked():
            if os.path.exists(os.path.join(case_folder, 'test_label.npy')):
                test_pred = np.load(
                    os.path.join(case_folder, 'test_predict.npy'))
                test_label = np.load(
                    os.path.join(case_folder, 'test_label.npy'))
                pred_list.append(test_pred)
                label_list.append(test_label)
                name_list.append('Test')

        if len(pred_list) > 0:
            DrawROCList(pred_list,
                        label_list,
                        name_list=name_list,
                        is_show=False,
                        fig=self.canvasROC.getFigure())

        self.canvasROC.draw()