Skip to content

Commit

Permalink
ENH: Add LIMS support (See #93)
Browse files Browse the repository at this point in the history
This commit updates CellLocator and Slicer adding support for flags `--lims-specimen-id`
and `--lims-base-url`.

If `--lims-specimen-id` is provided, it is used:
* At application startup time to
   (1) retrieve the corresponding annotation from LIMS and load it by using the `/specimen_metadata/view` endpoint.
   (2) enable the "Upload Annotation" button
* After user initiate annotation upload to LIMS while using the `/specimen_metadata/store` endpoint.

The "kind" parameter for both  endpoints `/specimen_metadata/view` and `/specimen_metadata/store`
is set to "IVSCC cell locations"

IVSCC expected cell count is currently unsupported.

For testing this functionality, a mock server as been implemented. Relevant instructions
are available here: https://github.com/KitwareMedical/AllenInstituteMockLIMS

List of Slicer changes:

$ git shortlog 0661948e5..9b00dc521f --no-merges
David Allemang (1):
      [cell-locator] ENH: Add command line args --lims-specimen-id and --lims-base-url for LIMS integration.
  • Loading branch information
allemangD authored and jcfr committed Jul 30, 2020
1 parent 8007438 commit e35c18f
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if(NOT DEFINED slicersources_SOURCE_DIR)
# Download Slicer sources and set variables slicersources_SOURCE_DIR and slicersources_BINARY_DIR
FetchContent_Populate(slicersources
GIT_REPOSITORY git://github.com/KitwareMedical/Slicer
GIT_TAG 0661948e52a7c809002954088bd3a8f847dc888d # cell-locator-v4.11.0-2018-12-19-0dc589ee5
GIT_TAG 9b00dc521fa993d0c3f266890fdae90c3c9945ca # cell-locator-v4.11.0-2018-12-19-0dc589ee5
GIT_PROGRESS 1
)
else()
Expand Down
99 changes: 99 additions & 0 deletions Modules/Scripted/Home/Home.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import os
import json
import logging
import shutil
import textwrap
import urllib
import urllib2
import urlparse

import vtk, qt, ctk, slicer

Expand Down Expand Up @@ -124,6 +128,10 @@ def postStartupInitialization():
if annotationFilePath:
self.loadAnnotationFile(annotationFilePath)

limsSpecimenID = slicer.app.commandOptions().limsSpecimenID
if limsSpecimenID:
self.loadLIMSSpecimen(limsSpecimenID)

qt.QTimer.singleShot(0, lambda: postStartupInitialization())

def isAnnotationSavingRequired(self):
Expand Down Expand Up @@ -271,6 +279,96 @@ def loadAnnotationFile(self, filename):
self.onAnnotationLoaded(loadedNode)
return success

def loadAnnotationJson(self, body):
tempdir = os.path.join(slicer.app.temporaryPath, 'json')
tempfile = os.path.join(tempdir, 'annotation.json')

if not (os.path.exists(tempdir) and os.path.isdir(tempdir)):
os.mkdir(tempdir)

with open(tempfile, 'w') as f:
json.dump(body, f)

self.loadAnnotationFile(tempfile)
self.MarkupsAnnotationNode.GetStorageNode().ResetFileNameList()
self.updateGUIFromMRML()

shutil.rmtree(tempdir)

def loadLIMSSpecimen(self, specimenID):
logging.info('Loading LIMS specimen id %s', specimenID)

base = slicer.app.commandOptions().limsBaseURL or 'http://localhost:5000/'
path = '/specimen_metadata/view'
url = urlparse.urljoin(base, path)

query = urllib.urlencode({
'kind': 'IVSCC cell locations',
'specimen_id': specimenID
})

try:
res = urllib2.urlopen('%s?%s' % (url, query))
except urllib2.URLError as e:
logging.error('Failed to connect to LIMS server.')
return

if res.getcode() != 200:
logging.error('Failed to load specimen ID %s from LIMS server.', specimenID)
return

body = json.loads(res.read())

self.loadAnnotationJson(body['data']['data'])

def onUploadAnnotationButtonClicked(self):
logging.info('Upload Annotation Button Clicked')

limsSpecimenID = slicer.app.commandOptions().limsSpecimenID
self.saveLIMSSpecimen(self.MarkupsAnnotationNode, limsSpecimenID)

def saveLIMSSpecimen(self, annotationNode, specimenID):
logging.info('Saving LIMS specimen id %s', specimenID)

data = self.saveAnnotationJson(annotationNode)

base = slicer.app.commandOptions().limsBaseURL or 'http://localhost:5000/'
path = '/specimen_metadata/store'
url = urlparse.urljoin(base, path)

body = json.dumps({
'kind': 'IVSCC cell locations',
'specimen_id': specimenID,
'data': data
})

try:
res = urllib2.urlopen(url, data=body)
except urllib2.URLError as e:
logging.error('Failed to connect to LIMS server')
return

if res.getcode() != 200:
logging.error('Failed to store specimen ID %s to LIMS server.', specimenID)

def saveAnnotationJson(self, annotationNode):
tempdir = os.path.join(slicer.app.temporaryPath, 'json')
tempfile = os.path.join(tempdir, 'annotation.json')

if not (os.path.exists(tempdir) and os.path.isdir(tempdir)):
os.mkdir(tempdir)

slicer.util.saveNode(annotationNode, tempfile)
self.logic.annotationStored(annotationNode)
self.updateGUIFromMRML()

with open(tempfile, 'r') as f:
data = json.load(f)

shutil.rmtree(tempdir)

return data

def onAnnotationLoaded(self, newAnnotationNode):

sliceNode = slicer.mrmlScene.GetNodeByID('vtkMRMLSliceNodeSlice')
Expand Down Expand Up @@ -987,6 +1085,7 @@ def setupConnections(self):
self.get('SaveAnnotationButton').connect("clicked()", self.onSaveAnnotationButtonClicked)
self.get('SaveAsAnnotationButton').connect("clicked()", self.onSaveAsAnnotationButtonClicked)
self.get('LoadAnnotationButton').connect("clicked()", self.onLoadAnnotationButtonClicked)
self.get('UploadAnnotationButton').connect("clicked()", self.onUploadAnnotationButtonClicked)

self.get('ResetFieldOfViewButton').connect("clicked()", self.resetFieldOfView)
self.get('ReferenceViewComboBox').connect("currentTextChanged(QString)", self.setReferenceView)
Expand Down
16 changes: 16 additions & 0 deletions Modules/Scripted/Home/Resources/UI/Home.ui
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QPushButton" name="UploadAnnotationButton">
<property name="text">
<string>Save to LIMS</string>
</property>
<property name="icon">
<iconset>
<normalon>:/Icons/save_icon.svg.png</normalon>
</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="ctkPathLineEdit" name="AnnotationPathLineEdit">
<property name="enabled">
Expand Down

0 comments on commit e35c18f

Please sign in to comment.