How to setup subject hierarchy tree filtering?

I’m currently having difficulty filtering the subject hierarchy using the attribute filter API. The following illustrates the unexpected behavior upon using setAttributeFilter. Does anyone know why this may be happening?

tree_view = slicer.qMRMLSubjectHierarchyTreeView()
tree_view.setMRMLScene(slicer.mrmlScene)
line_node_1 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line1")
line_node_2 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line2")
line_node_1.SetAttribute("Name", "Value")

image

tree_view.displayedItemCount() is 2

tree_view.setAttributeFilter("Name", "Value")

image

tree_view.displayedItemCount() is 0, although it was expected to be 1.

You may also want to look in the recent changes related to filtering that were introduced in BUG: Fix SubjectHierarchyGenericSelfTest by cpinter · Pull Request #7289 · Slicer/Slicer · GitHub

The setAttributeFilter method sets an attribute filter for items and not nodes. This is why when you set a node attribute but then were filtering on item attribute it did not show anything. It is also deprecated. See

Please use these properties instead:

The node and item attribute filters have their different properties, as well as their include and exclude variants.

@cpinter Is that deprecation comment wrong in that it says Sets and returns the first attribute in \sa includeNodeAttributeNamesFilter when actually it should be Sets and returns the first attribute in \sa includeItemAttributeNamesFilter?

Also does this mean the non-deprecated API can only filter by attribute name and not also by attribute value like SetAttributeFilter could do?

  1. You’re right, the comment is referencing the wrong function, it should be includeItemAttributeNamesFilter.

  2. No, you can still filter by value, see

I think the best thing to do would be to fix that comment in (1), and add an actual deprecation warning in the bodies of setAttributeNameFilter and setAttributeValueFilter.

Yes I agree with those improvements.

Since there are some methods specific to items and others for nodes it was getting a bit confusing. I was thinking of “item” as a generic term about a thing in a list of things which could be a node object.

Here’s an update to my original example code that shows how to successfully filter using node attributes.

tree_view = slicer.qMRMLSubjectHierarchyTreeView()
tree_view.setMRMLScene(slicer.mrmlScene)
line_node_1 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line1")
line_node_2 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line2")
line_node_1.SetAttribute("Name", "Value")
tree_view.displayedItemCount()  # 2

tree_view.addNodeAttributeFilter("Name", "Value")
tree_view.displayedItemCount()  # 1

tree_view.removeNodeAttributeFilter("Name", "Value")
tree_view.displayedItemCount()  # 2
1 Like

The following should help clarify

  1. Create the tree view

    tree_view = slicer.qMRMLSubjectHierarchyTreeView()
    tree_view.setMRMLScene(slicer.mrmlScene)
    line_node_1 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line1")
    line_node_2 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsLineNode", "Line2")
    
    assert tree_view.displayedItemCount() == 2
    
  2. Set the node attribute

    :warning: Adding a node attribute is different from a subject hierarchy item attribute

    line_node_1.SetAttribute("Name", "Value")
    
  3. Add a subject hierarchy item attribute fltter

    tree_view.addItemAttributeFilter("Name", "Value")
    

    … and as “expected” there are no item displayed

    assert tree_view.displayedItemCount() == 0
    
  4. Set the subject hierarchy item attribute

    shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
    shItem1 = shNode.GetItemByDataNode(line_node_1)
    shItem2 = shNode.GetItemByDataNode(line_node_2)
    
    shNode.SetItemAttribute(shItem1, "Name", "Value")
    
    # After setting the corrresponding item attribute, the items are filtered as expected
    assert tree_view.displayedItemCount() == 1
    
1 Like

For reference, deprecation warnings and improved documentation are being integrated through the following pull request: