Subject hierarchy
Get the pseudo-singleton subject hierarchy node
It manages the whole hierarchy and provides functions to access and manipulate
shNode = slicer.mrmlScene.GetSubjectHierarchyNode()
Create subject hierarchy item
# If it is for a data node, it is automatically created, but the create function can be used to set parent:
shNode.CreateItem(parentItemID, dataNode)
# If it is a hierarchy item without a data node, then the create function must be used:
shNode.CreateSubjectItem(parentItemID, name)
shNode.CreateFolderItem(parentItemID, name)
shNode.CreateHierarchyItem(parentItemID, name, level) # Advanced method to set level attribute manually (usually subject, study, or folder, but it can be a virtual branch for example)
Get subject hierarchy item
Items in subject hierarchy are uniquely identified by integer IDs
# Get scene item ID first because it is the root item:
sceneItemID = shNode.GetSceneItemID()
# Get direct child by name
subjectItemID = shNode.GetItemChildWithName(sceneItemID, "Subject_1")
# Get item for data node
itemID = shNode.GetItemByDataNode(dataNode)
# Get item by UID (such as DICOM)
itemID = shNode.GetItemByUID(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(), seriesInstanceUid)
itemID = shNode.GetItemByUIDList(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMInstanceUIDName(), instanceUID)
# Invalid item ID for checking validity of a given ID (most functions return the invalid ID when item is not found)
invalidItemID = slicer.vtkMRMLSubjectHierarchyNode.GetInvalidItemID()
Traverse children of a subject hierarchy item
children = vtk.vtkIdList()
shNode.GetItemChildren(parent, children) # Add a third argument with value True for recursive query
for i in range(children.GetNumberOfIds()):
child = children.GetId(i)
...
Manipulate subject hierarchy item
Instead of node operations on the individual subject hierarchy nodes, item operations are performed on the one subject hierarchy node.
# Set item name
shNode.SetItemName(itemID, "NewName")
# Set item parent (reparent)
shNode.SetItemParent(itemID, newParentItemID)
# Set visibility of data node associated to an item
shNode.SetItemDisplayVisibility(itemID, 1)
# Set visibility of whole branch
# Note: Folder-type items (fodler, subject, study, etc.) create their own display nodes when show/hiding from UI.
# The displayable managers use SH information to determine visibility of an item, so no need to show/hide individual leaf nodes any more.
# Once the folder display node is created, it can be shown hidden simply using shNode.SetItemDisplayVisibility
# From python, this is how to trigger creating a folder display node
pluginHandler = slicer.qSlicerSubjectHierarchyPluginHandler().instance()
folderPlugin = pluginHandler.pluginByName("Folder")
folderPlugin.setDisplayVisibility(folderItemID, 1)
Filter items in TreeView or ComboBox
Displayed items can be filtered using setAttributeFilter method. An example of the usage can be found in the unit test. Modified version here:
print(shTreeView.displayedItemCount()) # 5
shTreeView.setAttributeFilter("DICOM.Modality") # Nodes must have this attribute
print(shTreeView.displayedItemCount()) # 3
shTreeView.setAttributeFilter("DICOM.Modality","CT") # Have attribute and equal ``CT``
print(shTreeView.displayedItemCount()) # 1
shTreeView.removeAttributeFilter()
print(shTreeView.displayedItemCount()) # 5
Listen to subject hierarchy item events
The subject hierarchy node sends the node item id as calldata. Item IDs are vtkIdType, which are NOT vtkObjects. You need to use vtk.calldata_type(vtk.VTK_LONG) (otherwise the application crashes).
class MyListenerClass(VTKObservationMixin):
def __init__(self):
VTKObservationMixin.__init__(self)
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
self.addObserver(shNode, shNode.SubjectHierarchyItemModifiedEvent, self.shItemModifiedEvent)
@vtk.calldata_type(vtk.VTK_LONG)
def shItemModifiedEvent(self, caller, eventId, callData):
print("SH Node modified")
print("SH item ID: {0}".format(callData))
Save files to directory structure matching subject hierarchy folders
This code snippet saves all the storable files (volumes, transforms, markups, etc.) into a folder structure that mirrors the structure of the subject hierarchy tree (file folders have the same name as subject hierarchy folders).
def exportNodes(shFolderItemId, outputFolder):
# Get items in the folder
childIds = vtk.vtkIdList()
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
shNode.GetItemChildren(shFolderItemId, childIds)
if childIds.GetNumberOfIds() == 0:
return
# Create output folder
import os
os.makedirs(outputFolder, exist_ok=True)
# Write each child item to file
for itemIdIndex in range(childIds.GetNumberOfIds()):
shItemId = childIds.GetId(itemIdIndex)
# Write node to file (if storable)
dataNode = shNode.GetItemDataNode(shItemId)
if dataNode and dataNode.IsA("vtkMRMLStorableNode") and dataNode.GetStorageNode():
storageNode = dataNode.GetStorageNode()
filename = os.path.basename(storageNode.GetFileName())
filepath = outputFolder + "/" + filename
slicer.util.exportNode(dataNode, filepath)
# Write all children of this child item
grandChildIds = vtk.vtkIdList()
shNode.GetItemChildren(shItemId, grandChildIds)
if grandChildIds.GetNumberOfIds() > 0:
exportNodes(shItemId, outputFolder+"/"+shNode.GetItemName(shItemId))
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
outputFolder = "c:/tmp/test20211123"
slicer.app.ioManager().addDefaultStorageNodes()
exportNodes(shNode.GetSceneItemID(), outputFolder)