def open(self, username="", password=""): """Open the MorphoSource page and fill in or capture the url """ if username != "": self.setLogin(username, password) webWidget = slicer.qSlicerWebWidget() slicerGeometry = slicer.util.mainWindow().geometry webWidget.size = qt.QSize(slicerGeometry.width(), slicerGeometry.height()) webWidget.pos = qt.QPoint(slicerGeometry.x() + 256, slicerGeometry.y() + 128) webWidget.url = "https://www.morphosource.org/LoginReg/form" webWidget.show() self.webWidget = webWidget # TODO: need to expose loadFinished signal from QWebEngine via qSlicerWebWidget # so that we will know when to send this (current 2 second delay is a hack # that may not always work). onFinishLoading = lambda: self.onFinishLoading(username, password) connected = self.webWidget.connect('loadFinished(bool)', onFinishLoading) if not connected: qt.QTimer.singleShot( 3000, lambda: self.onFinishLoading(username, password)) return self.webWidget
def onSiteButtonClicked(self, site): webWidget = slicer.qSlicerWebWidget() slicerGeometry = slicer.util.mainWindow().geometry webWidget.size = qt.QSize(1536,1024) webWidget.pos = qt.QPoint(slicerGeometry.x() + 256, slicerGeometry.y() + 128) webWidget.url = site["url"] webWidget.show() self.webWidgets.append(webWidget)
def createWebWidget(): webWidget = slicer.qSlicerWebWidget() slicerGeometry = slicer.util.mainWindow().geometry webWidget.size = qt.QSize(slicerGeometry.width(), slicerGeometry.height()) webWidget.pos = qt.QPoint(slicerGeometry.x() + 256, slicerGeometry.y() + 128) webWidget.url = "http://localhost:8000" webWidget.show() return webWidget
def launchCovictory(self, url): lm = slicer.app.layoutManager() lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalWidescreenView) lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutConventionalView) splitter = lm.threeDWidget(0).parent() self.webWidget = slicer.qSlicerWebWidget() self.webWidget.url = url splitter = lm.threeDWidget(0).parent() splitter.insertWidget(0, self.webWidget) lm.threeDWidget(0).hide() sizes = [int(splitter.height*.67), 0, int(splitter.height*.33)] splitter.setSizes(sizes)
def onOpenSpecimenPage(self): selection = self.resultsTable.selectionModel().selectedRows() row = selection[0].row() specimen_id = self.result_dataframe.iloc[row].specimen_id url = base_specimen_page_url + '/' + specimen_id specimen_page = slicer.qSlicerWebWidget() geometry = slicer.util.mainWindow().geometry geometry.setLeft(geometry.left() + 50) geometry.setTop(geometry.top() + 50) geometry.setWidth(1080) geometry.setHeight(990) specimen_page.setGeometry(geometry) specimen_page.url = url specimen_page.show() self.specimen_pages.append(specimen_page)
def parallelCoordinatesPureD3(self): """Use parallel axes to explore parameter space See: http://syntagmatic.github.io/parallel-coordinates/ Note also experimented with vtk version, but it has fewer features and performance is not any better in practice. https://vtk.org/Wiki/VTK/Examples/Python/Infovis/ParallelCoordinatesExtraction """ self.volumeStatistics() fa = self.arrays['dtd_covariance_FA'] indices = numpy.where(fa != 0) samples = {} for key in self.arrays.keys(): samples[key] = self.arrays[key][indices] dataToPlot = [] for index in range(len(samples['dtd_covariance_FA'])): indexData = {} for key in self.arrays.keys(): scalarLabel = key[len('dtd_covariance_'):] indexData[scalarLabel] = samples[key][index] dataToPlot.append(indexData) dataToPlotString = json.dumps(dataToPlot) modulePath = os.path.dirname(slicer.modules.multimapper.path) resourceFilePath = os.path.join(modulePath, "Resources", "parallel-template.html") html = open(resourceFilePath).read().replace("%%dataToPlot%%", dataToPlotString) self.webWidget = slicer.qSlicerWebWidget() self.webWidget.size = qt.QSize(1024, 512) self.webWidget.setHtml(html) self.webWidget.show() open('/tmp/data.html', 'w').write(html)
def test_WebEngine1(self): """ Testing WebEngine """ self.delayDisplay("Starting the test") webWidget = slicer.qSlicerWebWidget() webWidget.size = qt.QSize(1024, 512) webWidget.webView().url = qt.QUrl("") webWidget.show() self.delayDisplay('Showing widget') webWidget.evalJS(""" const paragraph = document.createElement('p'); paragraph.innerText = 'Hello from Slicer!'; document.body.appendChild(paragraph); """) self.delayDisplay('Slicer should be saying hello!') # # Test javascript evaluation + use of "evalResult()" signal # webWidget.connect("evalResult(QString,QString)", self.onEvalResult) self.delayDisplay('Slicer setting a javascript value') webWidget.evalJS("const valueFromSlicer = 42;") webWidget.evalJS("valueFromSlicer;") iteration = 0 while not self.gotResponse and iteration < 3: # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for response...', msec=500) iteration += 1 webWidget.disconnect("evalResult(QString,QString)", self.onEvalResult) if not self.gotResponse: raise RuntimeError("Never got response from evalJS") if not self.gotCorrectResponse: raise AssertionError("Did not get back expected result!") # # Test python evaluation from javascript # self.delayDisplay('Call a python method') slicer.app.settings().setValue("WebEngine/AllowPythonExecution", ctk.ctkMessageBox.AcceptRole) webWidget.evalJS(r""" let pythonCode = "dialog = qt.QInputDialog(slicer.util.mainWindow())\n"; pythonCode += "dialog.setLabelText('hello')\n"; pythonCode += "dialog.open()\n"; pythonCode += "qt.QTimer.singleShot(1000, dialog.close)\n"; window.slicerPython.evalPython(pythonCode); """) self.delayDisplay('Test access to python via js', msec=500) if hasattr(slicer.modules, 'slicerPythonValueFromJS'): del slicer.modules.slicerPythonValueFromJS webWidget.evalJS(""" window.slicerPython.evalPython("slicer.modules.slicerPythonValueFromJS = 42"); """) iteration = 0 while iteration < 3 and not hasattr(slicer.modules, 'slicerPythonValueFromJS'): # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for python value from JS...', msec=500) iteration += 1 if iteration >= 3: raise RuntimeError("Couldn't get python value back from JS") self.delayDisplay('Value of %d received via javascipt' % slicer.modules.slicerPythonValueFromJS) del slicer.modules.slicerPythonValueFromJS self.delayDisplay('Test passed!')
def test_WebEngine1(self): """ Testing WebEngine """ self.delayDisplay("Starting the test") webWidget = slicer.qSlicerWebWidget() webWidget.size = qt.QSize(1024,512) webWidget.webView().url = qt.QUrl("") webWidget.show() self.delayDisplay('Showing widget') webWidget.evalJS(""" const paragraph = document.createElement('p'); paragraph.innerText = 'Hello from Slicer!'; document.body.appendChild(paragraph); """) self.delayDisplay('Slicer should be saying hello!') # # Test javascript evaluation + use of "evalResult()" signal # webWidget.connect("evalResult(QString,QString)", self.onEvalResult) self.delayDisplay('Slicer setting a javascript value') webWidget.evalJS("const valueFromSlicer = 42;") webWidget.evalJS("valueFromSlicer;"); iteration = 0 while not self.gotResponse and iteration < 3: # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for response...', msec=500) iteration += 1 webWidget.disconnect("evalResult(QString,QString)", self.onEvalResult) if not self.gotResponse: raise RuntimeError("Never got response from evalJS") if not self.gotCorrectResponse: raise AssertionError("Did not get back expected result!") # # Test python evaluation from javascript # self.delayDisplay('Call a python method') slicer.app.settings().setValue("WebEngine/AllowPythonExecution", ctk.ctkMessageBox.AcceptRole) webWidget.evalJS(r""" let pythonCode = "dialog = qt.QInputDialog(slicer.util.mainWindow())\n"; pythonCode += "dialog.setLabelText('hello')\n"; pythonCode += "dialog.open()\n"; pythonCode += "qt.QTimer.singleShot(1000, dialog.close)\n"; window.slicerPython.evalPython(pythonCode); """) self.delayDisplay('Test access to python via js', msec=500) if hasattr(slicer.modules, 'slicerPythonValueFromJS'): del slicer.modules.slicerPythonValueFromJS webWidget.evalJS(""" window.slicerPython.evalPython("slicer.modules.slicerPythonValueFromJS = 42"); """) iteration = 0 while iteration < 3 and not hasattr(slicer.modules, 'slicerPythonValueFromJS'): # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for python value from JS...', msec=500) iteration += 1 if iteration >= 3: raise RuntimeError("Couldn't get python value back from JS") self.delayDisplay('Value of %d received via javascipt' % slicer.modules.slicerPythonValueFromJS) del slicer.modules.slicerPythonValueFromJS self.delayDisplay('Test passed!')
def parallelCoordinatesParCoords_RandomSample(self, sampleSize=1000): """Use parallel axes to explore parameter space See: http://syntagmatic.github.io/parallel-coordinates/ https://github.com/BigFatDog/parcoords-es Note also experimented with vtk version, but it has fewer features and performance is not any better in practice. https://vtk.org/Wiki/VTK/Examples/Python/Infovis/ParallelCoordinatesExtraction """ self.volumeStatistics() fa = self.arrays['dtd_covariance_FA'] indices = numpy.where(fa != 0) ijkCoordinates = numpy.transpose(indices) ijkToRAS = vtk.vtkMatrix4x4() slicer.util.getNode('dtd_covariance_FA').GetIJKToRASMatrix(ijkToRAS) rasCoordinates = [] samples = {} for key in self.arrays.keys(): samples[key] = self.arrays[key][indices] dataToPlot = [] randomSample = random.sample(range(len(samples['dtd_covariance_FA'])), sampleSize) sampleIndex = 0 for index in randomSample: indexData = {} for key in self.arrays.keys(): scalarLabel = key[len('dtd_covariance_'):] indexData[scalarLabel] = samples[key][index] dataToPlot.append(indexData) ijk = [*numpy.flip(numpy.transpose(indices)[index]), 1] rasCoordinates.append(ijkToRAS.MultiplyPoint(ijk)) sampleIndex += 1 dataToPlotString = json.dumps(dataToPlot) rasCoordinatesString = json.dumps(rasCoordinates) modulePath = os.path.dirname(slicer.modules.multimapper.path) resourceFilePath = os.path.join(modulePath, "Resources", "ParCoords-template.html") html = open(resourceFilePath).read() html = html.replace("%%dataToPlot%%", dataToPlotString) html = html.replace("%%rasCoordinates%%", rasCoordinatesString) self.webWidget = slicer.qSlicerWebWidget() self.webWidget.size = qt.QSize(1024, 768) self.webWidget.setHtml(html) self.webWidget.show() def crosshairCallback(observer, eventID): crosshairNode = slicer.mrmlScene.GetFirstNodeByClass( 'vtkMRMLCrosshairNode') ras = [ 0, ] * 3 crosshairNode.GetCursorPositionRAS(ras) print(ras) # TODO: update selector ranges based on QTI statistics crosshairNode = slicer.mrmlScene.GetFirstNodeByClass( 'vtkMRMLCrosshairNode') event = vtk.vtkCommand.ModifiedEvent id_ = crosshairNode.AddObserver(event, crosshairCallback) self.observerObjectIDPairs.append((crosshairNode, id_)) # save for debugging open('/tmp/data.html', 'w').write(html)
def parallelCoordinatesSegmentation(self, segmentationNode=None, labelmapNode=None): """ Like parallelCoordinatesParCoords_RandomSample below, but parcoords plot created from segmentation """ self.volumeStatistics() if not segmentationNode: try: segmentationNode = slicer.util.getNode('Segmentation') except slicer.util.MRMLNodeNotFoundException: pass if not segmentationNode: print("need a segmentation") slicer.util.selectModule("SegmentEditor") return if not labelmapNode: try: labelmapNode = slicer.util.getNode('Segmentation-labelmap') except slicer.util.MRMLNodeNotFoundException: labelmapNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode') labelmapNode.SetName("Segmentation-labelmap") segmentIDs = vtk.vtkStringArray() segmentationNode.GetSegmentation().GetSegmentIDs(segmentIDs) slicer.modules.segmentations.logic().ExportSegmentsToLabelmapNode( segmentationNode, segmentIDs, labelmapNode, self.nodes['dtd_covariance_FA']) labelArray = slicer.util.arrayFromVolume(labelmapNode) # list of non-zero segments in the labelmap segmentIndices = list(numpy.unique(labelArray))[1:] # data colors to match the segmentation colors to pass to js segmentation = segmentationNode.GetSegmentation() dataColors = [[0, 0, 0]] for colorNumber in range(len(segmentIndices)): dataColor = segmentation.GetNthSegment(colorNumber).GetColor() dataColors.append(dataColor) # make individual sample lines for parallel coordinates ijkToRAS = vtk.vtkMatrix4x4() labelmapNode.GetIJKToRASMatrix(ijkToRAS) rasCoordinates = [] dataToPlot = [] for segmentIndex in segmentIndices: # one data sample from each array per labeled voxel coordinates = numpy.transpose( numpy.where(labelArray == segmentIndex)) self._coordinates = coordinates samples = {} for key in self.arrays.keys(): samples[key] = [] for coordinate in coordinates: self._array = self.arrays[key] samples[key].append(self.arrays[key][coordinate[0]][ coordinate[1]][coordinate[2]]) for coordinateNumber in range(len(coordinates)): indexData = {} indexData['segmentIndex'] = int(segmentIndex) for key in self.arrays.keys(): scalarLabel = key[len('dtd_covariance_'):] indexData[scalarLabel] = samples[key][coordinateNumber] dataToPlot.append(indexData) ijkw = [*numpy.flip(coordinates)[coordinateNumber], 1] ijkw = [*numpy.flip(coordinates)[coordinateNumber], 1] rasCoordinate = ijkToRAS.MultiplyPoint(ijkw) rasCoordinates.append(rasCoordinate) dataColorsString = json.dumps(dataColors) dataToPlotString = json.dumps(dataToPlot) rasCoordinatesString = json.dumps(rasCoordinates) modulePath = os.path.dirname(slicer.modules.multimapper.path) resourceFilePath = os.path.join(modulePath, "Resources", "ParCoords-SEG-template.html") html = open(resourceFilePath).read() html = html.replace("%%dataColors%%", dataColorsString) html = html.replace("%%dataToPlot%%", dataToPlotString) html = html.replace("%%rasCoordinates%%", rasCoordinatesString) self.webWidget = slicer.qSlicerWebWidget() self.webWidget.size = qt.QSize(1024, 768) self.webWidget.setHtml(html) self.webWidget.show() def crosshairCallback(observer, eventID): crosshairNode = slicer.mrmlScene.GetFirstNodeByClass( 'vtkMRMLCrosshairNode') ras = [ 0, ] * 3 crosshairNode.GetCursorPositionRAS(ras) print(ras) # TODO: update selector ranges based on QTI statistics crosshairNode = slicer.mrmlScene.GetFirstNodeByClass( 'vtkMRMLCrosshairNode') event = vtk.vtkCommand.ModifiedEvent id_ = crosshairNode.AddObserver(event, crosshairCallback) self.observerObjectIDPairs.append((crosshairNode, id_)) # save for debugging open('/tmp/data.html', 'w').write(html)
def openQtLocalConnection(self): self.webWidget = slicer.qSlicerWebWidget() self.webWidget.url = f'http://localhost:{self.logic.port}' self.webWidget.show()