Python FAQ¶
Frequently asked questions about how to write Python scripts for Slicer.
How to run a CLI module from Python¶
Here’s an example to create a model from a volume using the “Grayscale Model Maker” module:
def createModelFromVolume(inputVolumeNode):
"""Create surface mesh from volume node using CLI module"""
# Set parameters
parameters = {}
parameters["InputVolume"] = inputVolumeNode
outputModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode")
parameters["OutputGeometry"] = outputModelNode
# Execute
grayMaker = slicer.modules.grayscalemodelmaker
cliNode = slicer.cli.runSync(grayMaker, None, parameters)
# Process results
if cliNode.GetStatus() & cliNode.ErrorsMask:
# error
errorText = cliNode.GetErrorText()
slicer.mrmlScene.RemoveNode(cliNode)
raise ValueError("CLI execution failed: " + errorText)
# success
slicer.mrmlScene.RemoveNode(cliNode)
return outputModelNode
To try this, download the MRHead dataset using “Sample Data” module and paste the code above into the Python console and then run this:
volumeNode = getNode('MRHead')
modelNode = createModelFromVolume(volumeNode)
A complete example for running a CLI module from a scripted module is available here
Get list of parameter names¶
The following script prints all the parameter names of a CLI parameter node:
cliModule = slicer.modules.grayscalemodelmaker
n=cliModule.cliModuleLogic().CreateNode()
for groupIndex in range(n.GetNumberOfParameterGroups()):
print(f'Group: {n.GetParameterGroupLabel(groupIndex)}')
for parameterIndex in range(n.GetNumberOfParametersInGroup(groupIndex)):
print(' {0} [{1}]: {2}'.format(n.GetParameterName(groupIndex, parameterIndex),
n.GetParameterTag(groupIndex, parameterIndex),n.GetParameterLabel(groupIndex, parameterIndex)))
Passing markups iducials to CLIs¶
import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
head = sampleDataLogic.downloadMRHead()
volumesLogic = slicer.modules.volumes.logic()
headLabel = volumesLogic.CreateLabelVolume(slicer.mrmlScene, head, 'head-label')
fiducialNode = slicer.vtkMRMLAnnotationFiducialNode()
fiducialNode.SetFiducialWorldCoordinates((1,0,5))
fiducialNode.SetName('Seed Point')
fiducialNode.Initialize(slicer.mrmlScene)
fiducialsList = getNode('Fiducials List')
params = {'inputVolume': head.GetID(), 'outputVolume': headLabel.GetID(), 'seed' : fiducialsList.GetID(), 'iterations' : 2}
cliNode = slicer.cli.runSync(slicer.modules.simpleregiongrowingsegmentation, None, params)
Running CLI in the background¶
If the CLI module is executed using slicer.cli.run
method then the CLI module runs in a background thread, so the call to startProcessing
will return right away and the user interface will not be blocked. The slicer.cli.run
call returns a cliNode (an instance of vtkMRMLCommandLineModuleNode) which can be used to monitor the progress of the module.
In this example we create a simple callback onProcessingStatusUpdate
that will be called whenever the cliNode is modified. The status will tell you if the nodes is Pending, Running, or Completed.
def startProcessing(inputVolumeNode):
"""Create surface mesh from volume node using CLI module"""
# Set parameters
parameters = {}
parameters["InputVolume"] = inputVolumeNode
outputModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode")
parameters["OutputGeometry"] = outputModelNode
# Start execution in the background
grayMaker = slicer.modules.grayscalemodelmaker
cliNode = slicer.cli.run(grayMaker, None, parameters)
return cliNode
def onProcessingStatusUpdate(cliNode, event):
print("Got a %s from a %s" % (event, cliNode.GetClassName()))
if cliNode.IsA('vtkMRMLCommandLineModuleNode'):
print("Status is %s" % cliNode.GetStatusString())
if cliNode.GetStatus() & cliNode.Completed:
if cliNode.GetStatus() & cliNode.ErrorsMask:
# error
errorText = cliNode.GetErrorText()
print("CLI execution failed: " + errorText)
else:
# success
print("CLI execution succeeded. Output model node ID: "+cliNode.GetParameterAsString("OutputGeometry"))
volumeNode = getNode('MRHead')
cliNode = startProcessing(volumeNode)
cliNode.AddObserver('ModifiedEvent', onProcessingStatusUpdate)
# If you need to cancel the CLI, call
# cliNode.Cancel()
How to find a Python function for any Slicer features¶
All features of Slicer are available via Python scripts. Slicer script repository contains examples for the most commonly used features.
To find out what Python commands correspond to a feature that is visible on the graphical user interface, search in Slicer’s source code where that text occurs, find the corresponding widget or action name, then search for that widget or action name in the source code to find out what commands it triggers.
Complete example: How to emulate selection of FOV, spacing match Volumes
checkbox in the slice view controller menu?
- Go to Slicer project repository on github
- Enter text that you see on the GUI near the function that you want to use. In this case, enter
"FOV, spacing match Volumes"
(adding quotes around the text makes sure it finds that exact text) - Usually the text is found in a .ui file, in this case it is in qMRMLSliceControllerWidget.ui, open the file
- Find the text in the page, and look up what is the name of the widget or action that it is associated with - in this case it is an action named
actionSliceModelModeVolumes
- Search for that widget or action name in the repository, you should find a source file(s) that use it. In this case it will is qMRMLSliceControllerWidget.cxx
- Search for the action/widget name, and you’ll find what it does - in this case it calls
setSliceModelModeVolumes
method, which callsthis->setSliceModelMode(vtkMRMLSliceNode::SliceResolutionMatchVolumes)
, which then callsd->MRMLSliceNode->SetSliceResolutionMode(mode)
- This means that this action calls
someSliceNode->SetSliceResolutionMode(vtkMRMLSliceNode::SliceResolutionMatchVolumes)
in Python syntax it issomeSliceNode.SetSliceResolutionMode(slicer.vtkMRMLSliceNode.SliceResolutionMatchVolumes)
. For example, for the red slice node this will be:
sliceNode = slicer.mrmlScene.GetNodeByID('vtkMRMLSliceNodeRed')
sliceNode.SetSliceResolutionMode(slicer.vtkMRMLSliceNode.SliceResolutionMatchVolumes)
How to type file paths in Python¶
New Python users on Windows often suprised when they enter a path that contain backslash character (\
) and it just does not work. Since backslash (\
) is an escape character in Python, it requires special attention when used in string literals. For example, this is incorrect:
somePath = "F:\someFolder\myfile.nrrd" # incorrect (\s and \m are interpreted as special characters)
The easiest method for using a path that contains backslash character is to declare the text as “raw string” by prepending an r
character. This is correct:
somePath = r"F:\someFolder\myfile.nrrd"
It is possible to keep the text as regular string and typing double-backslash instead of . This is correct:
somePath = "F:\\someFolder\\myfile.nrrd"
In most places, unix-type separators can be used instead of backslash. This is correct:
somePath = "F:/someFolder/myfile.nrrd"
See more information in Python documentation: https://docs.python.org/3/tutorial/introduction.html?#strings
How to include Python modules in an extension¶
Sometimes, it is convenient to add Python modules to the Slicer scripted loadable modules. For example, the files associated with a Slicer module could look like this:
.
├── CMakeLists.txt
├── MySlicerModuleLib
│ ├── __init__.py
│ ├── cool_maths.py
│ └── utils.py
└── MySlicerModule.py
So that the following code can run within MySlicerModule.py
:
from MySlicerModuleLib import utils, cool_maths
By default, only the Slicer module (MySlicerModule.py
) will be downloaded when installing the extension using the Extensions Manager (see a related issue on GitHub).
To make sure all the necessary files are downloaded, the CMakeLists.txt
file associated with the Slicer module needs to be modified.
Initially, the second section of CMakeLists.txt
will look like this:
set(MODULE_PYTHON_SCRIPTS
${MODULE_NAME}.py
)
All the necessary files need to be added to the list. In our example:
set(MODULE_PYTHON_SCRIPTS
${MODULE_NAME}.py
${MODULE_NAME}Lib/__init__
${MODULE_NAME}Lib/utils
${MODULE_NAME}Lib/cool_maths
)
Note that the .py
extension is not necessary.