Modification of model's color in a vtkMRMLSequenceNode

Hi everyone!

I am trying to create a python scripted module using Sequences extension and I have an issue to modify the color of the models in a sequence: I would like to have different color for each model contained in the sequence created.
Here are the two codes that I tried:

First try: Change of the models’ colors before adding them to the sequence.

sequence = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceNode())
sequencebrowser = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceBrowserNode())
model0 = slicer.util.loadModel(“path/to/model0.vtk”,True)[1]
model1 = slicer.util.loadModel(“path/to/model1.vtk”,True)[1]
displayNode0 = model0.GetDisplayNode()
displayNode0.SetColor(1,0,0)
displayNode1 = model1.GetDisplayNode()
displayNode1.SetColor(1,1,0)
sequence.SetDataNodeAtValue(model0, “0”)
sequence.SetDataNodeAtValue(model1, “1”)
sequencebrowser.AddSynchronizedSequenceNodeID(sequence.GetID())

→ The models in the sequence stay gray: that’s probably due to the copy of the models in the sequence which didn’t copy the display nodes of the models.

Second try: Change of the models’ colors after adding them to the sequence.

sequence = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceNode())
sequencebrowser = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceBrowserNode())
model0 = slicer.util.loadModel(“path/to/model0.vtk”,True)[1]
model1 = slicer.util.loadModel(“path/to/model1.vtk”,True)[1]
model00 = sequence.SetDataNodeAtValue(model0, “0”)
model01 = sequence.SetDataNodeAtValue(model1, “1”)
displayNode0 = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelDisplayNode())
displayNode0.SetColor(1, 0, 0)
displayNode0.VisibilityOff()
displayNode1 = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelDisplayNode())
displayNode1.SetColor(1, 1, 0)
displayNode1.VisibilityOff()
model00.SetAndObserveDisplayNodeID(displayNode0.GetID())
model01.SetAndObserveDisplayNodeID(displayNode1.GetID())
model00.HideFromEditorsOn()
model01.HideFromEditorsOn()
slicer.mrmlScene.AddNode(model00)
slicer.mrmlScene.AddNode(model01)
sequencebrowser.AddSynchronizedSequenceNodeID(sequence.GetID())

I checked the existence of the display node in one of the model added to the sequence.

print sequence.GetDataNodeAtValue(“0”).GetDisplayNode()
vtkMRMLModelDisplayNode (0x1310b1600)
ID: vtkMRMLModelDisplayNode6
Debug: Off
Modified Time: 877045
Name: ModelDisplay_2
Description: (none)
SingletonTag: (none)
HideFromEditors: 1
Selectable: 1
Selected: 0
Indent: 0
Color: 0x1310b1848
SelectedColor: 0x1310b1878
SelectedAmbient: 0.4
SelectedSpecular: 0.5
Opacity: 1
Ambient: 0
Diffuse: 1
Specular: 0
Power: 1
Visibility: 1
ScalarVisibility: 0
VectorVisibility: 0
TensorVisibility: 0
InterpolateTexture:0
ScalarRangeFlag: 2
AutoScalarRange: 1
BackfaceCulling: 1
Clipping: 0
SliceIntersectionVisibility: 0
SliceIntersectionThickness: 1
ScalarRange: 0, 1
ColorNodeID: (none)
ActiveScalarName: (none)

print sequence.GetDataNodeAtValue(“0”).GetDisplayNode().GetColor()
(1.0, 0.0, 0.0)

→ Even if it seems that the display nodes exist, the models in the sequence also stay gray.

Do you have any idea of what is wrong? Any help will be appreciated! Thanks in advance!
Laura

If you want to make the display properties change in time, too, then you have to create a sequence node for the Model Display node (the same way as you create a sequence node for the Model node).

Thank you for your response!
As you suggested, I tried with the following code to create a second sequence node containing the model display nodes corresponding to the model nodes, unfortunately, it still doesn’t work. Am I still doing something wrong?

model0 = slicer.util.loadModel("path/to/model0.vtk",True)[1]
model1 = slicer.util.loadModel("/path/to/model1.vtk",True)[1]
model0.GetDisplayNode().VisibilityOff()
model0.GetDisplayNode().SetColor(1, 0, 0)
model1.GetDisplayNode().VisibilityOff()
model1.GetDisplayNode().SetColor(1, 1, 0)

sequence = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceNode())
sequence.SetDataNodeAtValue(model0, "0")
sequence.SetDataNodeAtValue(model1, "1")
 
displayNodeSequence = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceNode())
displayNodeSequence.SetDataNodeAtValue(model0.GetDisplayNode(), "0")
displayNodeSequence.SetDataNodeAtValue(model1.GetDisplayNode(), "1")

sequencebrowser = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceBrowserNode())
sequencebrowser.AddSynchronizedSequenceNodeID(displayNodeSequence.GetID())
sequencebrowser.AddSynchronizedSequenceNodeID(sequence.GetID())

@laurapascal As a side note, to cite code you can simply enclose it with back-ticks. I updated your last response accordingly.

You got it almost right. What you missed is replacing the default display node of the model proxy node by the temporally changing display node:

# Create model node sequence

modelSequence = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSequenceNode")

model = slicer.util.loadModel("path/to/file1",True)[1]
modelSequence.SetDataNodeAtValue(model, "0")
slicer.mrmlScene.RemoveNode(model.GetDisplayNode())
slicer.mrmlScene.RemoveNode(model)

model = slicer.util.loadModel("path/to/file2",True)[1]
modelSequence.SetDataNodeAtValue(model, "1")
slicer.mrmlScene.RemoveNode(model.GetDisplayNode())
slicer.mrmlScene.RemoveNode(model)

# Create display node sequence

displayNodeSequence = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSequenceNode")
displayNodeSequence.SetHideFromEditors(0)

modelDisplay = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelDisplayNode")

modelDisplay.SetColor(1, 0, 0)
displayNodeSequence.SetDataNodeAtValue(modelDisplay, "0")

modelDisplay.SetColor(0, 1, 0)
displayNodeSequence.SetDataNodeAtValue(modelDisplay, "1")

slicer.mrmlScene.RemoveNode(modelDisplay)

# Create sequence browser node

sequencebrowser = slicer.mrmlScene.AddNode(slicer.vtkMRMLSequenceBrowserNode())

sequencebrowser.AddSynchronizedSequenceNodeID(modelSequence.GetID())
sequencebrowser.AddSynchronizedSequenceNodeID(displayNodeSequence.GetID())

# Replace default display node that is created automatically
# by the display proxy node
modelProxyNode = sequencebrowser.GetProxyNode(modelSequence)
modelDisplayProxyNode = sequencebrowser.GetProxyNode(displayNodeSequence)
slicer.mrmlScene.RemoveNode(modelProxyNode.GetDisplayNode())
modelProxyNode.SetAndObserveDisplayNodeID(modelDisplayProxyNode.GetID())

I will update methods like slicer.utils.loadModel to pass kwargs as properties to loadNodeFromFile, that way we should be able to simplify:

into

model = slicer.util.loadModel("path/to/file1",returnNode=True, show=False)[1]
modelSequence.SetDataNodeAtValue(model, "0")
slicer.mrmlScene.RemoveNode(model)

Thank you for your help: it works perfectly!

1 Like