Create new vtkMRMLModelHierarchyNode() and add models

Hi slicers,

This is a simple question:
I have a modelNodeA and modelNodeB.
Using Python, I would like to create a modelHierarchyNode and add my two model nodes inside. Can you please give me a hint?

Best,
Fernando

Hi Fernando,

This is how I do it in C++:

  vtkSmartPointer<vtkMRMLModelHierarchyNode> rootModelHierarchyNode = vtkSmartPointer<vtkMRMLModelHierarchyNode>::New();
  scene->AddNode(rootModelHierarchyNode);
  rootModelHierarchyNode->SetName(rootModelHierarchyNodeName.c_str());
  rootModelHierarchyNode->SetSingletonTag(rootModelHierarchyNodeName.c_str());

  if (!rootModelHierarchyNode->GetDisplayNode())
  {
    vtkSmartPointer<vtkMRMLModelDisplayNode> rootModelHierarchyDisplayNode = vtkSmartPointer<vtkMRMLModelDisplayNode>::New();
    scene->AddNode(rootModelHierarchyDisplayNode);
    rootModelHierarchyNode->SetAndObserveDisplayNodeID( rootModelHierarchyDisplayNode->GetID() );
  }

...

  vtkSmartPointer<vtkMRMLModelHierarchyNode> collimatorModelHierarchyNode = vtkSmartPointer<vtkMRMLModelHierarchyNode>::New();
  scene->AddNode(collimatorModelHierarchyNode);
  collimatorModelHierarchyNode->SetModelNodeID(collimatorModelNode->GetID());
  collimatorModelHierarchyNode->SetParentNodeID(rootModelHierarchyNode->GetID());
  collimatorModelHierarchyNode->HideFromEditorsOn();

Are you sure you want to build model hierarchy? What is your use case? You may be better off using subject hierarchy instead, as subject hierarchy is:

  • more robust: model hierarchy tree widget has some issues, for example sometimes items randomly change place within a branch
  • has much simpler API
  • has more features: you can define custom actions, you can save the order of nodes in the hierarchy into the scene, and you can group all kinds of related nodes in a branch, not just models
  • much faster

For example, to create a branch and put a node in it:

shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
newParentFolderItem = shNode.CreateFolderItem(shNode.GetSceneItemID(), "my folder")
volumeItem = shNode.GetItemByDataNode(getNode('MRHead'))
shNode.SetItemParent(volumeItem, newParentFolderItem)
1 Like

Hi Csaba and Andras,

Thanks for your quick answers.

@cpinter My Python version:

modelNodeA = getNode('4648J_xscp_model')
modelNodeB = getNode('4648J_RH_lq_model')

rootModelHierarchyNodeName = 'My hierarchy'

rootModelHierarchyNode = slicer.vtkMRMLModelHierarchyNode()
slicer.mrmlScene.AddNode(rootModelHierarchyNode)
rootModelHierarchyNode.SetName(rootModelHierarchyNodeName)
rootModelHierarchyNode.SetSingletonTag(rootModelHierarchyNodeName)  # Not sure what this is

rootModelHierarchyDisplayNode = slicer.vtkMRMLModelDisplayNode()
slicer.mrmlScene.AddNode(rootModelHierarchyDisplayNode)
rootModelHierarchyNode.SetAndObserveDisplayNodeID(rootModelHierarchyDisplayNode.GetID())

modelAHierarchyNode = slicer.vtkMRMLModelHierarchyNode()
slicer.mrmlScene.AddNode(modelAHierarchyNode)
modelAHierarchyNode.SetModelNodeID(modelNodeA.GetID())
modelAHierarchyNode.SetParentNodeID(rootModelHierarchyNode.GetID())
modelAHierarchyNode.HideFromEditorsOn()  # Not sure what this is

modelBHierarchyNode = slicer.vtkMRMLModelHierarchyNode()
slicer.mrmlScene.AddNode(modelBHierarchyNode)
modelBHierarchyNode.SetModelNodeID(modelNodeB.GetID())
modelBHierarchyNode.SetParentNodeID(rootModelHierarchyNode.GetID())
modelBHierarchyNode.HideFromEditorsOn()

What I expect:

What I get:

I had already tried with some code I found (probably yours), and got similar results.

@lassoan I have a lot of models and I want to divide them in groups so that the user can easily change their display properties, using Slicer default modules if possible. I know there are some issues though…
I have never taken the time to look into subject hierarchy. It does looks simpler. Running your snippet makes a folder, from which I cannot modify the children display properties (at least I don’t know how to do it).

modelAHierarchyNode.HideFromEditorsOn() # Not sure what this is

This call is supposed to make the leaf hierarchy nodes disappear from the tree (to get from what you get to what you expect). Not sure why it doesn’t work, try SetHideFromEditors(1)

SetHideFromEditors(1) worked as expected. I tried to dive into the code to solve the issue I commented before, but I didn’t manage. Do you think it’s hard to fix?

Thank you again

You mean the slice intersection issue you linked?

I quickly took a look, and it seems that the checkbox in the Models module that applies color/opacity on the branch drives the vtkMRMLDisplayableHierarchyNode::Expanded flag, which is handled by the 3D displayable manager in vtkMRMLModelDisplayableManager::SetModelDisplayProperty, when getting the hierarchy display node (line 1488: vtkMRMLDisplayNode *hierarchyDisplayNode = this->GetHierarchyDisplayNode(model) ). This call is responsible for getting the right properties. The 2D displayable manager (vtkMRMLModelSliceDisplayableManager) does not use this, and this is what needs to be fixed.

I don’t have time to fix it, but I hope this will help. I’m adding this info on Mantis as well.

1 Like

Yes that’s what I meant. Thank you!

I created two model trees using this approach. I can access each tree and its children names. How can I get a model node from a specific child? e.g. to get their display node, polydata , …etc

  self.shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
  self.modelTreeID = self.shNode.GetItemChildWithName(self.shNode.GetSceneItemID(), "modelTreeName" ) 
  self.modelTreeChildrenIDs = vtk.vtkIdList()
  self.shNode.GetItemChildren(self.modelTreeID, self.modelTreeChildrenIDs)
  for i in xrange(self.modelTreeChildrenIDs GetNumberOfIds()):
      print("modelChildID   : ", self.modelTreeChildrenIDs.GetId(i)) 
      print("modelChildName : ", self.shNode.GetItemName(self.modelTreeChildrenIDs.GetId(i)))
1 Like

Model hierarchy is replaced by the much more generic subject hierarchy in recent Slicer versions. It should be easier to use and has many more capabilities. Script repository contains examples to most common tasks.

@lassoan thanks for your quick reply.

Model hierarchy is replaced by the much more generic subject hierarchy

I am using subject hierarchy, kindly see the code above.

. Script repository contains examples to most common tasks.

I already checked that. It is not clear to me how to get a “model node” from a child. I can get the child ID e.g. modelTreeChildrenIDs.GetId(i) or the chile name e.g. shNode.GetItemName(self.modelTreeChildrenIDs.GetId(i)) but not the model node.

You can get the model node using this function

1 Like

@cpinter Thanks a lot , this works, Here is the complete code I used:

self.shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
self.modelTreeID = self.shNode.GetItemChildWithName(self.shNode.GetSceneItemID(), "modelTreeName" ) 
self.modelTreeChildrenIDs = vtk.vtkIdList()
self.shNode.GetItemChildren(self.modelTreeID, self.modelTreeChildrenIDs)
for i in xrange(self.modelTreeChildrenIDs GetNumberOfIds()):
  print("modelChildID   : ", self.modelTreeChildrenIDs.GetId(i)) 
  print("modelChildName : ", self.shNode.GetItemName(self.modelTreeChildrenIDs.GetId(i)))
  print("modelChildNode  : ", self.shNode.GetItemDataNode(self.modelTreeChildrenIDs.GetId(i)))
1 Like