Source code for sparesplugin

from PyQt5.QtGui import *
from matplotlib.backends.backend_qt5 import FigureCanvasQT
from PyQt5 import QtGui, QtCore, QtWidgets, uic
import joblib
import sys, os, time
import seaborn as sns
import numpy as np
import pandas as pd
from NiBAx.core.plotcanvas import PlotCanvas
from NiBAx.core.baseplugin import BasePlugin
from NiBAx.core.gui.SearchableQComboBox import SearchableQComboBox
from NiBAx.plugins.sparesplugin.spares import SPARE

[docs]class SparePlugin(QtWidgets.QWidget,BasePlugin): #constructor def __init__(self): super(SparePlugin,self).__init__() self.model = {'BrainAge': None, 'AD': None} root = os.path.dirname(__file__) self.readAdditionalInformation(root) self.ui = uic.loadUi(os.path.join(root, 'sparesplugin.ui'),self) self.ui.comboBoxHue = SearchableQComboBox(self.ui) self.ui.horizontalLayout_3.addWidget(self.comboBoxHue) self.plotCanvas = PlotCanvas(self.ui.page_2) self.ui.verticalLayout.addWidget(self.plotCanvas) self.plotCanvas.axes = self.plotCanvas.fig.add_subplot(111) self.ui.stackedWidget.setCurrentIndex(0) self.ui.factorial_progressBar.setValue(0) self.spare_compute_instance = None
[docs] def getUI(self): return self.ui
[docs] def SetupConnections(self): self.ui.load_SPARE_model_Btn.clicked.connect(lambda: self.OnLoadSPAREModel()) self.ui.load_other_model_Btn.clicked.connect(lambda: self.OnLoadSPAREModel()) self.ui.add_to_dataframe_Btn.clicked.connect(lambda: self.OnAddToDataFrame()) self.ui.compute_SPARE_scores_Btn.clicked.connect(lambda check: self.OnComputeSPAREs(check)) self.ui.show_SPARE_scores_from_data_Btn.clicked.connect(lambda: self.OnShowSPAREs()) self.datamodel.data_changed.connect(lambda: self.OnDataChanged()) self.ui.comboBoxHue.currentIndexChanged.connect(self.plotSPAREs) self.ui.add_to_dataframe_Btn.setStyleSheet("background-color: green; color: white") # Set `Show SPARE-* from data` button to visible when SPARE-* columns # are present in data frame if ('SPARE_BA' in self.datamodel.GetColumnHeaderNames() and 'SPARE_AD' in self.datamodel.GetColumnHeaderNames()): self.ui.show_SPARE_scores_from_data_Btn.setStyleSheet("background-color: rgb(230,230,255)") self.ui.show_SPARE_scores_from_data_Btn.setEnabled(True) self.ui.show_SPARE_scores_from_data_Btn.setToolTip('The data frame has variables `SPARE_AD` and `SPARE_BA` so these can be plotted.') else: self.ui.show_SPARE_scores_from_data_Btn.setEnabled(False) # Allow loading of SPARE-* model always, even when residuals are not # calculated yet self.ui.load_SPARE_model_Btn.setEnabled(True)
[docs] def updateProgress(self, txt, vl): self.ui.SPARE_computation_info.setText(txt) self.ui.factorial_progressBar.setValue(vl)
[docs] def OnLoadSPAREModel(self): fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open SPARE-* model file', QtCore.QDir().homePath(), "Pickle files (*.pkl.gz *.pkl)") if fileName != "": self.model['BrainAge'], self.model['AD'] = joblib.load(fileName) self.ui.compute_SPARE_scores_Btn.setEnabled(True) self.ui.SPARE_model_info.setText('File: %s' % (fileName)) else: return self.ui.stackedWidget.setCurrentIndex(0) if 'RES_ICV_Sex_MUSE_Volume_47' in self.datamodel.GetColumnHeaderNames(): self.ui.compute_SPARE_scores_Btn.setStyleSheet("QPushButton" "{" "background-color : rgb(230,255,230);" "}" "QPushButton::checked" "{" "background-color : rgb(255,230,230);" "border: none;" "}" ) self.ui.compute_SPARE_scores_Btn.setEnabled(True) self.ui.compute_SPARE_scores_Btn.setChecked(False) self.ui.compute_SPARE_scores_Btn.setToolTip('Model loaded and `RES_ICV_Sex_MUSE_Volmue_*` available so the MUSE volumes can be harmonized.') else: self.ui.compute_SPARE_scores_Btn.setStyleSheet("background-color: rgb(255,230,230)") self.ui.compute_SPARE_scores_Btn.setEnabled(False) self.ui.compute_SPARE_scores_Btn.setToolTip('Model loaded but `RES_ICV_Sex_MUSE_Volmue_*` not available so the MUSE volumes can not be harmonized.') print('No field `RES_ICV_Sex_MUSE_Volume_47` found. ' + 'Make sure to compute and add harmonized residuals first.')
[docs] def OnComputationDone(self): spares = self.spare_compute_instance.SPAREs self.ui.compute_SPARE_scores_Btn.setText('Compute SPARE-*') if spares.empty: return self.ui.compute_SPARE_scores_Btn.setChecked(False) self.ui.stackedWidget.setCurrentIndex(1) self.ui.comboBoxHue.setVisible(False) self.plotSPAREs(False) # Activate buttons self.ui.compute_SPARE_scores_Btn.setEnabled(False) if ('SPARE_BA' in self.datamodel.GetColumnHeaderNames() and 'SPARE_AD' in self.datamodel.GetColumnHeaderNames()): self.ui.show_SPARE_scores_from_data_Btn.setEnabled(True) #self.ui.show_SPARE_scores_from_data_Btn.setStyleSheet("background-color: rgb(230,230,255)") else: self.ui.show_SPARE_scores_from_data_Btn.setEnabled(False) self.ui.load_SPARE_model_Btn.setEnabled(True)
[docs] def OnComputeSPAREs(self, checked): # Setup tasks for long running jobs # Using this example: https://realpython.com/python-pyqt-qthread/ # Disable buttons if checked is not True: self.spare_compute_instance.InterruptComputation() self.ui.compute_SPARE_scores_Btn.setStyleSheet("QPushButton" "{" "background-color : rgb(230,255,230);" "}" "QPushButton::checked" "{" "background-color : rgb(255,230,230);" "border: none;" "}" ) self.ui.compute_SPARE_scores_Btn.setText('Compute SPARE-*') self.ui.show_SPARE_scores_from_data_Btn.setEnabled(False) self.ui.load_SPARE_model_Btn.setEnabled(False) else: self.spare_compute_instance = SPARE(self.datamodel,self.model) self.ui.compute_SPARE_scores_Btn.setStyleSheet("QPushButton" "{" "background-color : rgb(230,255,230);" "}" "QPushButton::checked" "{" "background-color : rgb(255,230,230);" "}" ) self.ui.compute_SPARE_scores_Btn.setText('Cancel computation') self.ui.show_SPARE_scores_from_data_Btn.setEnabled(False) self.ui.load_SPARE_model_Btn.setEnabled(False) self.ui.factorial_progressBar.setRange(0, len(self.model['BrainAge']['scaler'])-1) self.spare_compute_instance.DoSPAREsComputation(True) self.spare_compute_instance.sendprogress.connect(self.updateProgress) self.spare_compute_instance.done.connect(self.OnComputationDone)
[docs] def PopulateHue(self): #add the list items to comboBoxHue datakeys = self.datamodel.GetColumnHeaderNames() datatypes = self.datamodel.GetColumnDataTypes() categoryList = ['Sex','Study','A','T','N','PIB_Status'] + [k for k,d in zip(datakeys, datatypes) if d.name=='category'] categoryList = list(set(categoryList).intersection(set(datakeys))) self.ui.comboBoxHue.clear() self.ui.comboBoxHue.addItems(categoryList)
[docs] def plotSPAREs(self, useExistingSPAREs=True): # Plot data if self.ui.stackedWidget.currentIndex() == 0: return self.plotCanvas.axes.clear() plotOptions = {'HUE': self.ui.comboBoxHue.currentText()} if useExistingSPAREs: #print(self.SPAREs[plotOptions['HUE']].value_counts()) print(self.spare_compute_instance.SPAREs[plotOptions['HUE']].value_counts()) kws = {"s": 20} sns.scatterplot(x='SPARE_AD', y='SPARE_BA', data=self.spare_compute_instance.SPAREs, ax=self.plotCanvas.axes, linewidth=0, hue=plotOptions['HUE'], facecolor=(0.5, 0.5, 0.5, 0.5), **kws) else: kws = {"s": 20} sns.scatterplot(x='SPARE_AD', y='SPARE_BA', data=self.spare_compute_instance.SPAREs, ax=self.plotCanvas.axes, linewidth=0, facecolor=(0.5, 0.5, 0.5, 0.5), legend=None) sns.despine(ax=self.plotCanvas.axes, trim=True) self.plotCanvas.axes.set(ylabel='SPARE-BA', xlabel='SPARE-AD') self.plotCanvas.axes.get_figure().set_tight_layout(True) self.plotCanvas.draw()
[docs] def OnAddToDataFrame(self): self.datamodel.AddSparesToDataModel(self.spare_compute_instance.SPAREs) self.OnShowSPAREs()
[docs] def OnShowSPAREs(self): allHues = [self.ui.comboBoxHue.itemText(i) for i in range(self.ui.comboBoxHue.count())] self.spare_compute_instance.SPAREs = self.datamodel.data[['SPARE_BA', 'SPARE_AD'] + allHues] self.ui.stackedWidget.setCurrentIndex(1) self.ui.comboBoxHue.setVisible(True) self.plotSPAREs()
[docs] def OnDataChanged(self): # Set `Show SPARE-* from data` button to visible when SPARE-* columns # are present in data frame self.ui.stackedWidget.setCurrentIndex(0) if ('SPARE_BA' in self.datamodel.GetColumnHeaderNames() and 'SPARE_AD' in self.datamodel.GetColumnHeaderNames()): self.ui.show_SPARE_scores_from_data_Btn.setEnabled(True) self.ui.show_SPARE_scores_from_data_Btn.setStyleSheet("background-color: rgb(230,230,255)") else: self.ui.show_SPARE_scores_from_data_Btn.setEnabled(False) self.PopulateHue()