How to link link a MarkUp point list to be a sequence in one SequenceBrowser using python script?

Hi everyone,

I am trying to write a module that can manually add landmarks using the MarkUp point list (vtkMRMLMarkupsFiducialNode) to different SequenceBrowsers.

I hope to link the point list node to one sequence of the target SequenceBrowser, and add an attribute of “pointListExist = True” to the SequenceBrowser.

What are the possible functions I should use to achieve it?

Thank you so much in advance!

You can create a new sequence node and add it to the sequence browser by calling AddProxyNode.

1 Like

Hi Andras,

Thank you so much for your help! I made it using AddProxyNode.

node_Browser 	= slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLSequenceBrowserNode')
node_Seq 		= slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSequenceNode", 'nodeSeq_pList_SeqBrowser_1')
node_Browser.AddProxyNode(getNode('pList_1'), node_Seq, False)

Could you please help me understand what is a ProxyNode? I would like to ask because I may not want it this way.
For all the other Proxy Node before and after a sequence recording, the ProxyNode share the same for different SequenceBrowsers; however, if I use AddProxyNode to link node_PoinList to the SequenceBrowser, I need multiple node_PointList (from ‘pList_1’ to ‘pList_n’) to be the ProxyNode for different SequenceBrowser, which is not ideal.

Could you please let me know what should I do?

The proxy node brings one item from the sequence into the scene.

Typically, each proxy node is used by one sequence browser node. However, if you are careful (e.g., don’t simultaneously replay two sequences that use the same proxy nodes) then you can use the same proxy nodes in multiple browsers, by setting copy argument toFalsewhen calling AddProxyNode.

So, in my case that each pList_Seq_n should be not only an independent PointList node that can be displayed in module MarkUp, but also should be the ProxyNode of 'SequenceBrowser_n' added by

node_SeqBrowser_n.AddProxyNode(getNode('pList_n'), node_Seq_n, True)

am I correct?

If yes, does that mean the actual PointList_n is saved twice, one in the format of 'vtkMRMLMarkupsFiducialNode', and the other one in the format of "vtkMRMLSequenceNode" ?

If you have one sequence node with many items then you can retrieve (and represent in the scene) one item by each browser node. So, there is some duplication, but by default a shallow-copy is performed from the sequence item into the proxy node, so bulk data (such as voxel array of an image) is not copied.

1 Like

Thank you so much, Andras!

I am not sure if using the MarkUp PointList (vtkMRMLMarkupsFiducialNode) would be the same case because it seems that there is not a node called MarkUp point (only PointList).

I need to call the MarkUp module to help SetActive a PointList node in order to add/drop a new control point, which means the copy has to be a shallow copy. Did I make sense?

In the meantime, to make sure I can find all PointList nodes in MarkUp module for different SequenceBrowser, I need to set copy=True when assigning a PointList to be the ProxyNode of a SequenceBrowser,

node_SeqBrowser_n.AddProxyNode(getNode('pList_n'), node_Seq_n, True)

would this achieve a sequence format, so that I can display the Point (if exists) of at different frames in a SequenceBrowser?

I might be confused about how to synchronize the MarkUp PointList (vtkMRMLMarkupsFiducialNode) to a SequenceBrowser.

Instead of making the node_PointList a ProxyNode, I should make the ControlPoint a ProxyNode, because each frame corresponds to one ControlPoint, am I correct?

However, ControlPoint is not a node. What should I do to make the PointList a synchronized SequenceNode in a SequenceBrowser?

Or, maybe I can create a PointList for every single frame in the SequenceBrowser, so that the PointList is the ProxyNode. In this case, what are the possible functions I should use to add/save the nodes of PointList in the SequenceBroswer?
In this case, I should not use slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode"), because it will then be added to the MarkUp module and shown in the Data module. How to make it only available in SequenceBrowser as a Sequence?

Changes in a proxy node are automatically saved into the sequence node if you enable SaveChanges for the sequence.

1 Like

So glad I made it !! :grin: To make it work, the newly added SequenceNode must be filled up by all empty PointList, otherwise the later annotated DataNode will always be affected by the previous added DataNode and the SequenceNode will not be able to Update during the PlayBack

Empty node_PointList: slicer.vtkMRMLMarkupsFiducialNode()
Fill Sequence: nodeSeq_Annotation.SetDataNodeAtValue(node_EmptyPointList, str_IndexValue_Time)

nodeSeqBrowser.AddProxyNode(node_SeqBrowserProxy_Annotation, nodeSeq_Annotation, False)
nodeSeqBrowser.SetSaveChanges(nodeSeq_Annotation, True)

#  Fill up the SequenceNode with all empty 'PointList'
num_DataNodes = nodeSeqBrowser.GetNumberOfItems()
nodeSeq_Image = nodeSeqBrowser.GetSequenceNode(slicer.util.getNode('Existing_ProxyNodeName'))
for idx_DataNode in range(num_DataNodes):
    str_IndexValue_Time = nodeSeq_Image.GetNthIndexValue(idx_DataNode)
    nodeSeq_Annotation.SetDataNodeAtValue(slicer.vtkMRMLMarkupsFiducialNode(), str_IndexValue_Time)