iraemmBrowser.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. import os
  2. import unittest
  3. from __main__ import vtk, qt, ctk, slicer
  4. from slicer.ScriptedLoadableModule import *
  5. import slicerNetwork
  6. import loadDicom
  7. import json
  8. import datetime
  9. #
  10. # labkeySlicerPythonExtension
  11. #
  12. class iraemmBrowser(ScriptedLoadableModule):
  13. """Uses ScriptedLoadableModule base class, available at:
  14. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  15. """
  16. def __init__(self, parent):
  17. ScriptedLoadableModule.__init__(self, parent)
  18. self.parent.title = "irAEMM Browser" # TODO make this more human readable by adding spaces
  19. self.parent.categories = ["LabKey"]
  20. self.parent.dependencies = []
  21. self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
  22. self.parent.helpText = """
  23. Interface to irAEMM files in LabKey
  24. """
  25. self.parent.acknowledgementText = """
  26. Developed within the medical physics research programme of the Slovenian research agency.
  27. """ # replace with organization, grant and thanks.
  28. #
  29. # labkeySlicerPythonExtensionWidget
  30. #
  31. class iraemmBrowserWidget(ScriptedLoadableModuleWidget):
  32. """Uses ScriptedLoadableModuleWidget base class, available at:
  33. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  34. """
  35. def setup(self):
  36. print("Setting up iraemmBrowserWidget")
  37. ScriptedLoadableModuleWidget.setup(self)
  38. # Instantiate and connect widgets ...
  39. self.network=slicerNetwork.labkeyURIHandler()
  40. fconfig=os.path.join(os.path.expanduser('~'),'.labkey','network.json')
  41. self.network.parseConfig(fconfig)
  42. self.network.initRemote()
  43. self.project="iPNUMMretro/Study"
  44. self.dataset="Imaging1"
  45. self.reviewDataset="ImageReview"
  46. self.aeDataset="PET"
  47. self.segmentList=['liver','bowel','thyroid','lung','kidney','pancreas']
  48. ds=self.network.filterDataset(self.project,self.dataset,[])
  49. ids=[row['PatientId'] for row in ds['rows']]
  50. ids=list(set(ids))
  51. #
  52. # Setup Area
  53. #
  54. setupCollapsibleButton = ctk.ctkCollapsibleButton()
  55. setupCollapsibleButton.text = "Setup"
  56. self.layout.addWidget(setupCollapsibleButton)
  57. setupFormLayout = qt.QFormLayout(setupCollapsibleButton)
  58. self.participantField=qt.QLabel("PatientId")
  59. setupFormLayout.addRow("Participant field:",self.participantField)
  60. self.ctField=qt.QLabel("ctResampled")
  61. setupFormLayout.addRow("Data field (CT):",self.ctField)
  62. self.petField=qt.QLabel("petResampled")
  63. setupFormLayout.addRow("Data field (PET):",self.petField)
  64. self.segmentationField=qt.QLabel("Segmentation")
  65. setupFormLayout.addRow("Data field (Segmentation):",self.segmentationField)
  66. self.logic=iraemmBrowserLogic(self)
  67. #
  68. # Patients Area
  69. #
  70. patientsCollapsibleButton = ctk.ctkCollapsibleButton()
  71. patientsCollapsibleButton.text = "Patients"
  72. self.layout.addWidget(patientsCollapsibleButton)
  73. patientsFormLayout = qt.QFormLayout(patientsCollapsibleButton)
  74. self.patientList=qt.QComboBox()
  75. for id in ids:
  76. self.patientList.addItem(id)
  77. self.patientList.currentIndexChanged.connect(self.onPatientListChanged)
  78. patientsFormLayout.addRow("Patient:",self.patientList)
  79. self.visitList=qt.QComboBox()
  80. self.visitList.currentIndexChanged.connect(self.onVisitListChanged)
  81. patientsFormLayout.addRow("Visit:",self.visitList)
  82. self.ctCode=qt.QLabel("ctCode")
  83. patientsFormLayout.addRow("CT:",self.ctCode)
  84. self.petCode=qt.QLabel("petCode")
  85. patientsFormLayout.addRow("PET:",self.petCode)
  86. self.segmentationCode=qt.QLabel("segmentationCode")
  87. patientsFormLayout.addRow("Segmentation",self.segmentationCode)
  88. self.patientLoad=qt.QPushButton("Load")
  89. self.patientLoad.clicked.connect(self.onPatientLoadButtonClicked)
  90. patientsFormLayout.addRow("Load patient",self.patientLoad)
  91. self.patientClear=qt.QPushButton("Clear")
  92. self.patientClear.clicked.connect(self.onPatientClearButtonClicked)
  93. patientsFormLayout.addRow("Clear patient",self.patientClear)
  94. self.keepCached=qt.QCheckBox("keep Cached")
  95. self.keepCached.setChecked(1)
  96. patientsFormLayout.addRow("Keep cached",self.keepCached)
  97. #set to a defined state
  98. self.onPatientListChanged(0)
  99. #
  100. # Review Area
  101. #
  102. reviewCollapsibleButton = ctk.ctkCollapsibleButton()
  103. reviewCollapsibleButton.text = "Review"
  104. self.layout.addWidget(reviewCollapsibleButton)
  105. self.reviewBoxLayout = qt.QVBoxLayout(reviewCollapsibleButton)
  106. self.reviewFormLayout = qt.QFormLayout()
  107. self.reviewSegment=qt.QComboBox()
  108. self.reviewSegment.currentIndexChanged.connect(self.onReviewSegmentChanged)
  109. self.reviewFormLayout.addRow("Selected region:",self.reviewSegment)
  110. self.reviewResult=qt.QComboBox()
  111. self.reviewFormLayout.addRow("What do you think about the segmentation:",\
  112. self.reviewResult)
  113. reviewOptions=['Select','Excellent','Minor deficiencies',\
  114. 'Major deficiencies','Unusable']
  115. for opt in reviewOptions:
  116. self.reviewResult.addItem(opt)
  117. self.aeResult=qt.QComboBox()
  118. self.reviewFormLayout.addRow("Is organ suffering from adverse effect?",\
  119. self.aeResult)
  120. aeOptions=['Select','Yes','No']
  121. for opt in aeOptions:
  122. self.aeResult.addItem(opt)
  123. #self.aeResult.setCurrentIndex(0)
  124. self.updateReview=qt.QPushButton("Save")
  125. self.reviewFormLayout.\
  126. addRow("Save segmentation and AE decision for current segment",\
  127. self.updateReview)
  128. self.updateReview.clicked.connect(self.onUpdateReviewButtonClicked)
  129. self.reviewBoxLayout.addLayout(self.reviewFormLayout)
  130. submitFrame=qt.QGroupBox("Submit data")
  131. self.submitFormLayout=qt.QFormLayout()
  132. self.reviewComment=qt.QTextEdit("this is a test")
  133. self.submitFormLayout.addRow("Comments (optional)",\
  134. self.reviewComment)
  135. self.submitReviewButton=qt.QPushButton("Submit")
  136. self.submitFormLayout.addRow("Submit to database",\
  137. self.submitReviewButton)
  138. self.submitReviewButton.clicked.connect(self.onSubmitReviewButtonClicked)
  139. submitFrame.setLayout(self.submitFormLayout)
  140. submitFrame.setFlat(1)
  141. #submitFrame.setFrameShape(qt.QFrame.StyledPanel)
  142. #submitFrame.setFrameShadow(qt.QFrame.Sunken)
  143. submitFrame.setStyleSheet("background-color:rgba(220,215,180,45)")
  144. self.reviewBoxLayout.addWidget(submitFrame)
  145. def onPatientListChanged(self,i):
  146. idFilter={'variable':'PatientId','value':self.patientList.currentText,'oper':'eq'}
  147. ds=self.network.filterDataset(self.project,self.dataset, [idFilter])
  148. seq=[int(row['SequenceNum']) for row in ds['rows']]
  149. self.visitList.clear()
  150. for s in seq:
  151. self.visitList.addItem("Visit "+str(s))
  152. self.onVisitListChanged(0)
  153. def onVisitListChanged(self,i):
  154. try:
  155. s=self.visitList.currentText.split(' ')[1]
  156. except IndexError:
  157. return
  158. print("Visit: Selected item: {}->{}".format(i,s))
  159. idFilter={'variable':'PatientId',\
  160. 'value':self.patientList.currentText,'oper':'eq'}
  161. sFilter={'variable':'SequenceNum','value':s,'oper':'eq'}
  162. ds=self.network.filterDataset(self.project,self.dataset,[idFilter,sFilter])
  163. if not len(ds['rows'])==1:
  164. print("Found incorrect number {} of matches for [{}]/[{}]".\
  165. format(len(ds['rows']),\
  166. self.patientList.currentText,s))
  167. row=ds['rows'][0]
  168. #copy row properties for data access
  169. self.currentRow=row
  170. self.petCode.setText(row[self.petField.text])
  171. self.ctCode.setText(row[self.ctField.text])
  172. self.segmentationCode.setText(row[self.segmentationField.text])
  173. def onPatientLoadButtonClicked(self):
  174. print("Load")
  175. #delegate loading to logic
  176. #try:
  177. self.logic.loadImage(self.currentRow,self.keepCached.isChecked())
  178. segmentList=self.logic.compileSegmentation()
  179. #also bladder,vertebraL1, stomach, heart
  180. for seg in segmentList:
  181. if not seg in self.segmentList:
  182. continue
  183. #filter to most important ones
  184. self.reviewSegment.addItem(seg)
  185. self.logic.loadReview(self.currentRow)
  186. self.logic.loadAE(self.currentRow)
  187. for segment in self.segmentList:
  188. rIdx=self.logic.getReviewResult(segment)
  189. aIdx=self.logic.getAEResult(segment)
  190. print("Segment {}: {}/{}".format(segment,rIdx,aIdx))
  191. try:
  192. if (rIdx+aIdx)>0:
  193. self.updateResult(segment,rIdx,aIdx)
  194. except TypeError:
  195. continue
  196. try:
  197. self.reviewComment.setPlainText(self.logic.reviewComment)
  198. except AttributeError:
  199. pass
  200. self.onReviewSegmentChanged()
  201. #except AttributeError:
  202. # print("Missing current row")
  203. # return
  204. def onReviewSegmentChanged(self):
  205. segment=self.reviewSegment.currentText
  206. self.logic.hideSegments()
  207. self.logic.showSegment(segment)
  208. #set reviewFlag to stored value
  209. self.reviewResult.setCurrentIndex(self.logic.getReviewResult(segment))
  210. self.aeResult.setCurrentIndex(self.logic.getAEResult(segment))
  211. def onSubmitReviewButtonClicked(self):
  212. print("Submit")
  213. print("Selected review:{}/{}".format(self.reviewResult.currentIndex,
  214. self.reviewResult.currentText))
  215. print("Comment:{}".format(self.reviewComment))
  216. self.logic.submitReview(self.currentRow,\
  217. self.reviewComment.plainText)
  218. self.logic.submitAE(self.currentRow)
  219. def onUpdateReviewButtonClicked(self):
  220. print("Save")
  221. segment=self.reviewSegment.currentText
  222. self.logic.updateReview(segment,\
  223. self.reviewResult.currentIndex)
  224. self.logic.updateAE(segment,\
  225. self.aeResult.currentIndex)
  226. self.updateResult(segment,self.reviewResult.currentIndex,\
  227. self.aeResult.currentIndex)
  228. def updateResult(self,segment,reviewResult,aeResult):
  229. reviewText=self.reviewResult.itemText(reviewResult)
  230. aeText=self.aeResult.itemText(aeResult)
  231. idx=self.findCompletedSegment(segment)
  232. if idx<0:
  233. qReview=qt.QLabel(reviewText)
  234. self.submitFormLayout.insertRow(0,segment,qReview)
  235. qAE=qt.QLabel(aeText)
  236. self.submitFormLayout.insertRow(1,segment+'AE',qAE)
  237. try:
  238. self.segmentsCompleted.append(segment)
  239. self.segmentsCompleted.append(segment+'AE')
  240. except AttributeError:
  241. self.segmentsCompleted=[]
  242. self.segmentsCompleted.append(segment)
  243. self.segmentsCompleted.append(segment+'AE')
  244. else:
  245. qReview=self.submitFormLayout.itemAt(idx,1).widget()
  246. qReview.setText(reviewText)
  247. qAE=self.submitFormLayout.itemAt(idx+1,1).widget()
  248. qAE.setText(aeText)
  249. reviewColors=['pink','green','yellow','orange','red']
  250. qReview.setStyleSheet("background-color: "+reviewColors[reviewResult])
  251. aeColors=['pink','red','green']
  252. qAE.setStyleSheet("background-color: "+aeColors[aeResult])
  253. def findCompletedSegment(self,segment):
  254. for i in range(self.submitFormLayout.rowCount()):
  255. if self.submitFormLayout.itemAt(i,0).widget().text==segment:
  256. return i
  257. return -1
  258. def removeCompletedSegments(self):
  259. try:
  260. segments=self.segmentsCompleted
  261. except AttributeError:
  262. return
  263. for seg in segments:
  264. idx=self.findCompletedSegment(seg)
  265. if idx>-1:
  266. self.submitFormLayout.removeRow(idx)
  267. self.segmentsCompleted=[]
  268. def onPatientClearButtonClicked(self):
  269. self.logic.clearVolumesAndSegmentations()
  270. self.reviewSegment.clear()
  271. self.removeCompletedSegments()
  272. self.reviewComment.clear()
  273. def cleanup(self):
  274. pass
  275. #
  276. # irAEMMBrowserLogic
  277. #
  278. class iraemmBrowserLogic(ScriptedLoadableModuleLogic):
  279. """This class should implement all the actual
  280. computation done by your module. The interface
  281. should be such that other python code can import
  282. this class and make use of the functionality without
  283. requiring an instance of the Widget.
  284. Uses ScriptedLoadableModuleLogic base class, available at:
  285. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  286. """
  287. def __init__(self,parent=None):
  288. ScriptedLoadableModuleLogic.__init__(self, parent)
  289. if not parent==None:
  290. #assume parent has the network set up
  291. self.parent=parent
  292. self.net=parent.network
  293. self.project=parent.project
  294. self.participantField=parent.participantField.text
  295. self.segmentList=parent.segmentList
  296. self.segLabel={'1':'liver','2':'spleen','3':'lung','4':'thyroid',\
  297. '5':'kidney','6':'pancreas','7':'gallbladder','8':'bladder',\
  298. '9':'aorta','10':'trachea','11':'sternum','12':'vertebraL1',\
  299. '13':'adrenal','14':'psoasMajor','15':'rectus',\
  300. '16':'bowel','17':'stomach','18':'heart'}
  301. def setLabkeyInterface(self,net):
  302. #additional way of setting the labkey network interface
  303. #if no parent was provided in logic initialization (stand-alone mode)
  304. self.net=net
  305. def setLabkeyProject(self,project):
  306. self.project=project
  307. def loadImage(self,row,keepCached):
  308. #fields={'ctResampled':True,'petResampled':False}
  309. fields={"CT":self.parent.ctField.text,\
  310. "PET":self.parent.petField.text,\
  311. "Segmentation":self.parent.segmentationField.text}
  312. relativePaths={x:self.project+'/@files/preprocessedImages/'\
  313. +row['patientCode']+'/'+row['visitCode']+'/'+row[y]\
  314. for (x,y) in fields.items()}
  315. self.volumeNode={}
  316. for f in relativePaths:
  317. p=relativePaths[f]
  318. labkeyPath=self.net.GetLabkeyPathFromRelativePath(p)
  319. rp=self.net.head(labkeyPath)
  320. if not slicerNetwork.labkeyURIHandler.HTTPStatus(rp):
  321. print("Failed to get {}".format(labkeyPath))
  322. continue
  323. #pushes it to background
  324. properties={}
  325. #make sure segmentation gets loaded as a labelmap
  326. if f=="Segmentation":
  327. properties["labelmap"]=1
  328. self.volumeNode[f]=self.net.loadNode(p,'VolumeFile',\
  329. properties=properties,returnNode=True,keepCached=keepCached)
  330. #mimic abdominalCT standardized window setting
  331. self.volumeNode['CT'].GetScalarVolumeDisplayNode().\
  332. SetWindowLevel(1400, -500)
  333. #set colormap for PET to PET-Heat (this is a verbatim setting from
  334. #the Volumes->Display->Lookup Table colormap identifier)
  335. self.volumeNode['PET'].GetScalarVolumeDisplayNode().\
  336. SetAndObserveColorNodeID(\
  337. slicer.util.getNode('PET-Heat').GetID())
  338. slicer.util.setSliceViewerLayers(background=self.volumeNode['CT'],\
  339. foreground=self.volumeNode['PET'],foregroundOpacity=0.1,fit=True)
  340. #segmentations
  341. def compileSegmentation(self):
  342. try:
  343. labelmapVolumeNode = self.volumeNode['Segmentation']
  344. except KeyError:
  345. print("No segmentaion volumeNode available")
  346. return
  347. self.segmentationNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')
  348. slicer.modules.segmentations.logic().\
  349. ImportLabelmapToSegmentationNode(labelmapVolumeNode, self.segmentationNode)
  350. segmentList=[]
  351. seg=self.segmentationNode.GetSegmentation()
  352. for i in range(seg.GetNumberOfSegments()):
  353. segment=seg.GetNthSegment(i)
  354. segment.SetName(self.segLabel[segment.GetName()])
  355. segmentList.append(segment.GetName())
  356. #seg.CreateClosedSurfaceRepresentation()
  357. slicer.mrmlScene.RemoveNode(labelmapVolumeNode)
  358. self.volumeNode.pop('Segmentation',None)
  359. #return list of segment names
  360. return segmentList
  361. def hideSegments(self):
  362. try:
  363. displayNode=self.segmentationNode.GetDisplayNode()
  364. except AttributeError:
  365. return
  366. seg=self.segmentationNode.GetSegmentation()
  367. for i in range(seg.GetNumberOfSegments()):
  368. #segment=self.segmentationNode.GetSegmentation().GetNthSegment(i)
  369. segmentID=seg.GetNthSegmentID(i)
  370. displayNode.SetSegmentVisibility(segmentID, False)
  371. #print("Done")
  372. def showSegment(self,name):
  373. try:
  374. displayNode=self.segmentationNode.GetDisplayNode()
  375. except AttributeError:
  376. return
  377. seg=self.segmentationNode.GetSegmentation()
  378. for i in range(seg.GetNumberOfSegments()):
  379. segment=seg.GetNthSegment(i)
  380. if not segment.GetName()==name:
  381. continue
  382. segmentID=seg.GetNthSegmentID(i)
  383. displayNode.SetSegmentVisibility(segmentID, True)
  384. break
  385. #print("Done")
  386. #clear
  387. def clearVolumesAndSegmentations(self):
  388. nodes=slicer.util.getNodesByClass("vtkMRMLVolumeNode")
  389. nodes.extend(slicer.util.getNodesByClass("vtkMRMLSegmentationNode"))
  390. res=[slicer.mrmlScene.RemoveNode(f) for f in nodes]
  391. self.segmentationNode=None
  392. self.reviewResult={}
  393. self.aeList={}
  394. #reviews by segment
  395. def updateReview(self,segment,value):
  396. try:
  397. self.reviewResult[segment]=value
  398. except AttributeError:
  399. self.reviewResult={}
  400. self.updateReview(segment,value)
  401. def getReviewResult(self,segment):
  402. try:
  403. return self.reviewResult[segment]
  404. except AttributeError:
  405. #review result not initialized
  406. return 0
  407. except KeyError:
  408. #segment not done yet
  409. return 0
  410. #load review from labkey
  411. def getUniqueRows(self, project, dataset, fields, inputRow):
  412. filters=[]
  413. for f in fields:
  414. filters.append({'variable':f,'value':str(inputRow[f]),'oper':'eq'})
  415. ds=self.net.filterDataset(project,dataset,filters)
  416. return ds['rows']
  417. def loadReview(self,currentRow):
  418. #see if we have already done a review
  419. rows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
  420. [self.participantField,'visitCode','Segmentation'],currentRow)
  421. if len(rows)==0:
  422. return
  423. row=rows[0]
  424. for label in self.segmentList:
  425. #name=self.segLabel[label]+'Review'
  426. name=label+'Review'
  427. try:
  428. self.updateReview(label,row[name])
  429. except KeyError:
  430. continue
  431. self.reviewComment=row['reviewComment']
  432. #submit review to labkey
  433. def submitReview(self,currentRow,comment):
  434. fields=[self.participantField,'visitCode','Segmentation']
  435. rows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
  436. fields,currentRow)
  437. mode='update'
  438. if len(rows)==0:
  439. mode='insert'
  440. row={}
  441. for f in fields:
  442. row[f]=currentRow[f]
  443. frows=self.getUniqueRows(self.parent.project,self.parent.reviewDataset,\
  444. [self.participantField,'visitCode'],currentRow)
  445. row['SequenceNum']=currentRow['SequenceNum']+0.01*len(frows)
  446. else:
  447. row=rows[0]
  448. seg=self.segmentationNode.GetSegmentation()
  449. for i in range(seg.GetNumberOfSegments()):
  450. segment=seg.GetNthSegment(i)
  451. fieldName=segment.GetName()+'Review'
  452. value=self.getReviewResult(segment.GetName())
  453. row[fieldName]=value
  454. row['reviewComment']=comment
  455. row['Date']=datetime.datetime.now().ctime()
  456. self.net.modifyDataset(mode,self.parent.project,\
  457. self.parent.reviewDataset,[row])
  458. print("review submitted")
  459. #AE management
  460. def updateAE(self,segment,value):
  461. try:
  462. self.aeList[segment]=value
  463. except AttributeError:
  464. self.aeList={}
  465. self.updateAE(segment,value)
  466. def getAEResult(self,segment):
  467. try:
  468. return self.aeList[segment]
  469. except AttributeError:
  470. #review result not initialized (unknown)
  471. return 0
  472. except KeyError:
  473. #segment not done yet (unknown)
  474. return 0
  475. def loadAE(self,currentRow):
  476. fields=[self.participantField,'petResampled']
  477. rows=self.getUniqueRows(self.parent.project,self.parent.aeDataset,\
  478. fields,currentRow)
  479. if len(rows)==0:
  480. return
  481. print("Found {} rows".format(len(rows)))
  482. row=rows[0]
  483. for seg in self.segmentList:
  484. name=seg+'AE'
  485. try:
  486. self.updateAE(seg,row[name])
  487. except AttributeError:
  488. continue
  489. except KeyError:
  490. continue
  491. def submitAE(self,currentRow):
  492. fields=[self.participantField,'petResampled']
  493. rows=self.getUniqueRows(self.parent.project,self.parent.aeDataset,\
  494. fields,currentRow)
  495. if len(rows)==0:
  496. mode='insert'
  497. row={}
  498. for f in fields:
  499. row[f]=currentRow[f]
  500. row['SequenceNum']=currentRow['SequenceNum']
  501. else:
  502. mode='update'
  503. row=rows[0]
  504. for seg in self.segmentList:
  505. row[seg+'AE']=self.getAEResult(seg)
  506. row['Date']=datetime.datetime.now().ctime()
  507. resp=self.net.modifyDataset(mode,self.parent.project,\
  508. self.parent.aeDataset,[row])
  509. print("Response {}".format(resp))
  510. print("AE submitted")
  511. class irAEMMBrowserTest(ScriptedLoadableModuleTest):
  512. """
  513. This is the test case for your scripted module.
  514. Uses ScriptedLoadableModuleTest base class, available at:
  515. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  516. """
  517. def setUp(self):
  518. """ Do whatever is needed to reset the state - typically a scene clear will be enough.
  519. """
  520. slicer.mrmlScene.Clear(0)
  521. def runTest(self):
  522. """Run as few or as many tests as needed here.
  523. """
  524. self.setUp()
  525. self.test_irAEMMBrowser()
  526. def test_irAEMMBrowser(self):
  527. """ Ideally you should have several levels of tests. At the lowest level
  528. tests sould exercise the functionality of the logic with different inputs
  529. (both valid and invalid). At higher levels your tests should emulate the
  530. way the user would interact with your code and confirm that it still works
  531. the way you intended.
  532. One of the most important features of the tests is that it should alert other
  533. developers when their changes will have an impact on the behavior of your
  534. module. For example, if a developer removes a feature that you depend on,
  535. your test should break so they know that the feature is needed.
  536. """
  537. self.delayDisplay("Starting the test")
  538. #
  539. # first, get some data
  540. #