|
@@ -50,9 +50,9 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
self.project="iPNUMMretro/Study"
|
|
|
self.dataset="Imaging1"
|
|
|
self.reviewDataset="ImageReview"
|
|
|
+ self.aeDataset="PET"
|
|
|
+ self.segmentList=['liver','bowel','thyroid','lung','kidney','pancreas']
|
|
|
|
|
|
-
|
|
|
- self.logic=iraemmBrowserLogic(self)
|
|
|
|
|
|
|
|
|
ds=self.network.filterDataset(self.project,self.dataset,[])
|
|
@@ -69,7 +69,9 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
|
|
|
setupFormLayout = qt.QFormLayout(setupCollapsibleButton)
|
|
|
|
|
|
-
|
|
|
+ self.participantField=qt.QLabel("PatientId")
|
|
|
+ setupFormLayout.addRow("Participant field:",self.participantField)
|
|
|
+
|
|
|
self.ctField=qt.QLabel("ctResampled")
|
|
|
setupFormLayout.addRow("Data field (CT):",self.ctField)
|
|
|
|
|
@@ -78,10 +80,12 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
|
|
|
self.segmentationField=qt.QLabel("Segmentation")
|
|
|
setupFormLayout.addRow("Data field (Segmentation):",self.segmentationField)
|
|
|
+
|
|
|
+ self.logic=iraemmBrowserLogic(self)
|
|
|
|
|
|
|
|
|
#
|
|
|
- # Patienrs Area
|
|
|
+ # Patients Area
|
|
|
#
|
|
|
patientsCollapsibleButton = ctk.ctkCollapsibleButton()
|
|
|
patientsCollapsibleButton.text = "Patients"
|
|
@@ -152,9 +156,17 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
for opt in reviewOptions:
|
|
|
self.reviewResult.addItem(opt)
|
|
|
|
|
|
+ self.aeResult=qt.QComboBox()
|
|
|
+ self.reviewFormLayout.addRow("Is organ suffering from adverse effect?",\
|
|
|
+ self.aeResult)
|
|
|
+ aeOptions=['Select','Yes','No']
|
|
|
+ for opt in aeOptions:
|
|
|
+ self.aeResult.addItem(opt)
|
|
|
+ #self.aeResult.setCurrentIndex(0)
|
|
|
+
|
|
|
self.updateReview=qt.QPushButton("Save")
|
|
|
self.reviewFormLayout.\
|
|
|
- addRow("Save segmentation decision for current segment",\
|
|
|
+ addRow("Save segmentation and AE decision for current segment",\
|
|
|
self.updateReview)
|
|
|
self.updateReview.clicked.connect(self.onUpdateReviewButtonClicked)
|
|
|
|
|
@@ -218,24 +230,40 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
#try:
|
|
|
self.logic.loadImage(self.currentRow,self.keepCached.isChecked())
|
|
|
segmentList=self.logic.compileSegmentation()
|
|
|
- importantSegmentList=['liver','bowel','thyroid','lung','spleen']
|
|
|
#also bladder,vertebraL1, stomach, heart
|
|
|
for seg in segmentList:
|
|
|
- if not seg in importantSegmentList:
|
|
|
+ if not seg in self.segmentList:
|
|
|
continue
|
|
|
#filter to most important ones
|
|
|
self.reviewSegment.addItem(seg)
|
|
|
self.logic.loadReview(self.currentRow)
|
|
|
+ self.logic.loadAE(self.currentRow)
|
|
|
+ for segment in self.segmentList:
|
|
|
+ rIdx=self.logic.getReviewResult(segment)
|
|
|
+ aIdx=self.logic.getAEResult(segment)
|
|
|
+ print("Segment {}: {}/{}".format(segment,rIdx,aIdx))
|
|
|
+ try:
|
|
|
+ if (rIdx+aIdx)>0:
|
|
|
+ self.updateResult(segment,rIdx,aIdx)
|
|
|
+ except TypeError:
|
|
|
+ continue
|
|
|
+ try:
|
|
|
+ self.reviewComment.setPlainText(self.logic.reviewComment)
|
|
|
+ except AttributeError:
|
|
|
+ pass
|
|
|
+
|
|
|
self.onReviewSegmentChanged()
|
|
|
#except AttributeError:
|
|
|
# print("Missing current row")
|
|
|
# return
|
|
|
|
|
|
def onReviewSegmentChanged(self):
|
|
|
+ segment=self.reviewSegment.currentText
|
|
|
self.logic.hideSegments()
|
|
|
- self.logic.showSegment(self.reviewSegment.currentText)
|
|
|
+ self.logic.showSegment(segment)
|
|
|
#set reviewFlag to stored value
|
|
|
- self.reviewResult.setCurrentIndex(self.logic.getReviewResult(self.reviewSegment.currentText))
|
|
|
+ self.reviewResult.setCurrentIndex(self.logic.getReviewResult(segment))
|
|
|
+ self.aeResult.setCurrentIndex(self.logic.getAEResult(segment))
|
|
|
|
|
|
def onSubmitReviewButtonClicked(self):
|
|
|
print("Submit")
|
|
@@ -244,29 +272,52 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
print("Comment:{}".format(self.reviewComment))
|
|
|
self.logic.submitReview(self.currentRow,\
|
|
|
self.reviewComment.plainText)
|
|
|
+ self.logic.submitAE(self.currentRow)
|
|
|
|
|
|
def onUpdateReviewButtonClicked(self):
|
|
|
print("Save")
|
|
|
|
|
|
- self.logic.updateReview(self.reviewSegment.currentText,\
|
|
|
+ segment=self.reviewSegment.currentText
|
|
|
+ self.logic.updateReview(segment,\
|
|
|
self.reviewResult.currentIndex)
|
|
|
-
|
|
|
- idx=self.findCompletedSegment(self.reviewSegment.currentText)
|
|
|
+
|
|
|
+ self.logic.updateAE(segment,\
|
|
|
+ self.aeResult.currentIndex)
|
|
|
+ self.updateResult(segment,self.reviewResult.currentIndex,\
|
|
|
+ self.aeResult.currentIndex)
|
|
|
+
|
|
|
+
|
|
|
+ def updateResult(self,segment,reviewResult,aeResult):
|
|
|
+ reviewText=self.reviewResult.itemText(reviewResult)
|
|
|
+ aeText=self.aeResult.itemText(aeResult)
|
|
|
+
|
|
|
+ idx=self.findCompletedSegment(segment)
|
|
|
+
|
|
|
if idx<0:
|
|
|
- qReview=qt.QLabel(self.reviewResult.currentText)
|
|
|
- self.submitFormLayout.insertRow(0,self.reviewSegment.currentText,qReview)
|
|
|
+ qReview=qt.QLabel(reviewText)
|
|
|
+ self.submitFormLayout.insertRow(0,segment,qReview)
|
|
|
+ qAE=qt.QLabel(aeText)
|
|
|
+ self.submitFormLayout.insertRow(1,segment+'AE',qAE)
|
|
|
try:
|
|
|
- self.segmentsCompleted.append(self.reviewSegment.currentText)
|
|
|
+ self.segmentsCompleted.append(segment)
|
|
|
+ self.segmentsCompleted.append(segment+'AE')
|
|
|
except AttributeError:
|
|
|
self.segmentsCompleted=[]
|
|
|
- self.segmentsCompleted.append(self.reviewSegment.currentText)
|
|
|
+ self.segmentsCompleted.append(segment)
|
|
|
+ self.segmentsCompleted.append(segment+'AE')
|
|
|
else:
|
|
|
qReview=self.submitFormLayout.itemAt(idx,1).widget()
|
|
|
- qReview.setText(self.reviewResult.currentText)
|
|
|
+ qReview.setText(reviewText)
|
|
|
+ qAE=self.submitFormLayout.itemAt(idx+1,1).widget()
|
|
|
+ qAE.setText(aeText)
|
|
|
+
|
|
|
+ reviewColors=['pink','green','yellow','orange','red']
|
|
|
+ qReview.setStyleSheet("background-color: "+reviewColors[reviewResult])
|
|
|
+ aeColors=['pink','red','green']
|
|
|
+ qAE.setStyleSheet("background-color: "+aeColors[aeResult])
|
|
|
+
|
|
|
+
|
|
|
|
|
|
- colors=['pink','green','yellow','orange','red']
|
|
|
- qReview.setStyleSheet("background-color: "+colors[self.reviewResult.currentIndex])
|
|
|
-
|
|
|
def findCompletedSegment(self,segment):
|
|
|
|
|
|
for i in range(self.submitFormLayout.rowCount()):
|
|
@@ -293,6 +344,7 @@ class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
|
|
|
self.logic.clearVolumesAndSegmentations()
|
|
|
self.reviewSegment.clear()
|
|
|
self.removeCompletedSegments()
|
|
|
+ self.reviewComment.clear()
|
|
|
|
|
|
|
|
|
|
|
@@ -323,6 +375,8 @@ class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
|
|
|
self.parent=parent
|
|
|
self.net=parent.network
|
|
|
self.project=parent.project
|
|
|
+ self.participantField=parent.participantField.text
|
|
|
+ self.segmentList=parent.segmentList
|
|
|
|
|
|
self.segLabel={'1':'liver','2':'spleen','3':'lung','4':'thyroid',\
|
|
|
'5':'kidney','6':'pancreas','7':'gallbladder','8':'bladder',\
|
|
@@ -330,6 +384,8 @@ class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
|
|
|
'13':'adrenal','14':'psoasMajor','15':'rectus',\
|
|
|
'16':'bowel','17':'stomach','18':'heart'}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
def setLabkeyInterface(self,net):
|
|
|
#additional way of setting the labkey network interface
|
|
|
#if no parent was provided in logic initialization (stand-alone mode)
|
|
@@ -449,6 +505,7 @@ class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
|
|
|
res=[slicer.mrmlScene.RemoveNode(f) for f in nodes]
|
|
|
self.segmentationNode=None
|
|
|
self.reviewResult={}
|
|
|
+ self.aeList={}
|
|
|
|
|
|
#reviews by segment
|
|
|
|
|
@@ -470,53 +527,58 @@ class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
|
|
|
return 0
|
|
|
|
|
|
#load review from labkey
|
|
|
- def loadReview(self,currentRow):
|
|
|
|
|
|
- #see if we have already done a review
|
|
|
+ def getUniqueRows(self, project, dataset, fields, inputRow):
|
|
|
filters=[]
|
|
|
- fields=['PatientId','SequenceNum']
|
|
|
-
|
|
|
|
|
|
for f in fields:
|
|
|
- filters.append({'variable':f,'value':str(currentRow[f]),'oper':'eq'})
|
|
|
+ filters.append({'variable':f,'value':str(inputRow[f]),'oper':'eq'})
|
|
|
+
|
|
|
|
|
|
- ds=self.net.filterDataset(self.parent.project,\
|
|
|
- self.parent.reviewDataset,filters)
|
|
|
+ ds=self.net.filterDataset(project,dataset,filters)
|
|
|
+ return ds['rows']
|
|
|
+
|
|
|
+ def loadReview(self,currentRow):
|
|
|
|
|
|
- if len(ds['rows'])==0:
|
|
|
+ #see if we have already done a review
|
|
|
+ rows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
|
|
|
+ [self.participantField,'visitCode','Segmentation'],currentRow)
|
|
|
+
|
|
|
+ if len(rows)==0:
|
|
|
return
|
|
|
|
|
|
- row=ds['rows'][0]
|
|
|
- for label in self.segLabel:
|
|
|
- name=self.segLabel[label]+'Review'
|
|
|
+ row=rows[0]
|
|
|
+ for label in self.segmentList:
|
|
|
+ #name=self.segLabel[label]+'Review'
|
|
|
+ name=label+'Review'
|
|
|
try:
|
|
|
- self.updateReview(self.segLabel[label],row[name])
|
|
|
+ self.updateReview(label,row[name])
|
|
|
except KeyError:
|
|
|
continue
|
|
|
-
|
|
|
+ self.reviewComment=row['reviewComment']
|
|
|
+
|
|
|
#submit review to labkey
|
|
|
def submitReview(self,currentRow,comment):
|
|
|
- row={}
|
|
|
+ fields=[self.participantField,'visitCode','Segmentation']
|
|
|
+ rows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
|
|
|
+ fields,currentRow)
|
|
|
|
|
|
- fields=['PatientId','SequenceNum']
|
|
|
|
|
|
- #see if we have to update or insert
|
|
|
- filters=[]
|
|
|
-
|
|
|
- for f in fields:
|
|
|
- filters.append({'variable':f,'value':str(currentRow[f]),'oper':'eq'})
|
|
|
+ mode='update'
|
|
|
|
|
|
- ds=self.net.filterDataset(self.parent.project,\
|
|
|
- self.parent.reviewDataset,filters)
|
|
|
-
|
|
|
- mode='insert'
|
|
|
-
|
|
|
- if len(ds['rows'])>0:
|
|
|
- row=ds['rows'][0]
|
|
|
- mode='update'
|
|
|
- else:
|
|
|
+ if len(rows)==0:
|
|
|
+ mode='insert'
|
|
|
+ row={}
|
|
|
for f in fields:
|
|
|
row[f]=currentRow[f]
|
|
|
+
|
|
|
+ frows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
|
|
|
+ [self.participantField,'visitCode'],currentRow)
|
|
|
+
|
|
|
+ row['SequenceNum']=currentRow['SequenceNum']+0.01*len(frows)
|
|
|
+
|
|
|
+ else:
|
|
|
+ row=rows[0]
|
|
|
|
|
|
seg=self.segmentationNode.GetSegmentation()
|
|
|
|
|
@@ -528,12 +590,83 @@ class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
|
|
|
|
|
|
row['reviewComment']=comment
|
|
|
row['Date']=datetime.datetime.now().ctime()
|
|
|
- ds=self.net.modifyDataset(mode,self.parent.project,\
|
|
|
+ self.net.modifyDataset(mode,self.parent.project,\
|
|
|
self.parent.reviewDataset,[row])
|
|
|
|
|
|
print("review submitted")
|
|
|
|
|
|
|
|
|
+#AE management
|
|
|
+ def updateAE(self,segment,value):
|
|
|
+ try:
|
|
|
+ self.aeList[segment]=value
|
|
|
+ except AttributeError:
|
|
|
+ self.aeList={}
|
|
|
+ self.updateAE(segment,value)
|
|
|
+
|
|
|
+ def getAEResult(self,segment):
|
|
|
+ try:
|
|
|
+ return self.aeList[segment]
|
|
|
+ except AttributeError:
|
|
|
+ #review result not initialized (unknown)
|
|
|
+ return 0
|
|
|
+ except KeyError:
|
|
|
+ #segment not done yet (unknown)
|
|
|
+ return 0
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ def loadAE(self,currentRow):
|
|
|
+ fields=[self.participantField,'petResampled']
|
|
|
+ rows=self.getUniqueRows(self.parent.project,self.parent.aeDataset,\
|
|
|
+ fields,currentRow)
|
|
|
+
|
|
|
+ if len(rows)==0:
|
|
|
+ return
|
|
|
+
|
|
|
+ print("Found {} rows".format(len(rows)))
|
|
|
+ row=rows[0]
|
|
|
+
|
|
|
+ for seg in self.segmentList:
|
|
|
+ name=seg+'AE'
|
|
|
+ try:
|
|
|
+ self.updateAE(seg,row[name])
|
|
|
+ except AttributeError:
|
|
|
+ continue
|
|
|
+ except KeyError:
|
|
|
+ continue
|
|
|
+
|
|
|
+ def submitAE(self,currentRow):
|
|
|
+ fields=[self.participantField,'petResampled']
|
|
|
+ rows=self.getUniqueRows(self.parent.project,self.parent.aeDataset,\
|
|
|
+ fields,currentRow)
|
|
|
+
|
|
|
+
|
|
|
+ if len(rows)==0:
|
|
|
+ mode='insert'
|
|
|
+ row={}
|
|
|
+ for f in fields:
|
|
|
+ row[f]=currentRow[f]
|
|
|
+
|
|
|
+ row['SequenceNum']=currentRow['SequenceNum']
|
|
|
+
|
|
|
+ else:
|
|
|
+ mode='update'
|
|
|
+ row=rows[0]
|
|
|
+
|
|
|
+ for seg in self.segmentList:
|
|
|
+ row[seg+'AE']=self.getAEResult(seg)
|
|
|
+
|
|
|
+ row['Date']=datetime.datetime.now().ctime()
|
|
|
+ resp=self.net.modifyDataset(mode,self.parent.project,\
|
|
|
+ self.parent.aeDataset,[row])
|
|
|
+ print("Response {}".format(resp))
|
|
|
+ print("AE submitted")
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
class irAEMMBrowserTest(ScriptedLoadableModuleTest):
|
|
|
|
|
|
"""
|