Link slices views by default?

Every time I load a close a scene or restart slicer, the slice views
become unlinked. Is there a way to make them linked by default?

1 Like

You could put something like this in your .slicerrc.py

for node in getNodesByClass('vtkMRMLSliceCompositeNode'):
  node.SetLinkedControl(1)

https://www.slicer.org/wiki/Documentation/Nightly/Developers/Python_scripting#How_to_systematically_execute_custom_python_code_at_startup_.3F

In addition to Steve’s code snippet above, to make all new slice viewers linked as well, you can change the default composite node properties like this:

defaultSliceCompositeNode = slicer.vtkMRMLSliceCompositeNode()
defaultSliceCompositeNode.SetLinkedControl(1)
slicer.mrmlScene.AddDefaultNode(defaultSliceCompositeNode)

This code has only effect on latest trunk version, as I’ve just fixed slice composite node creation to use scene’s CreateNodeByClass method instead of the node’s New method.

1 Like

Nice Andras! :+1:

If this feature is widely useful we could look into adding it as a settings option.

Out of sight! This works great!!

I think it would be useful to add the option as a setting. I consistently link the slice views as soon as I load an image.

It would be quite simple to implement this (just need to add it to qSlicerSettingsViewsPanel.cxx and qSlicerSettingsViewsPanel.ui), but since it can be set using .slicerrc file and not that many people have asked for this, the priority of implementing this is low. I would be happy to help you implementing this if you decide to give it a go.

1 Like

I am having issues with the following code

def makeSlicerLinkedCompositeNodes():
    # Set linked slice views  in all existing slice composite nodes and in the default node
    sliceCompositeNodes = slicer.util.getNodesByClass(
        "vtkMRMLSliceCompositeNode")
    defaultSliceCompositeNode = slicer.mrmlScene.GetDefaultNodeByClass(
        "vtkMRMLSliceCompositeNode")
    if not defaultSliceCompositeNode:
        defaultSliceCompositeNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLSliceCompositeNode")
        slicer.mrmlScene.AddDefaultNode(defaultSliceCompositeNode)
    for sliceCompositeNode in sliceCompositeNodes:
        sliceCompositeNode.SetLinkedControl(True)
    defaultSliceCompositeNode.SetLinkedControl(True)


def setSlicerViews(backgroundID, foregroundID):
    if not utils.checkTesting():
        makeSlicerLinkedCompositeNodes()

        slicer.util.setSliceViewerLayers(background=str(
            backgroundID), foreground=str(foregroundID), foregroundOpacity=0.5)

        slicer.app.layoutManager().setLayout(
            slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView)
        slicer.util.resetSliceViews()
        slicer.app.processEvents()

It creates extra composite nodes.

Is there a better way to set background and foreground in a forced linked views scheme?

It is not necessary to add default nodes to the scene, so instead of AddNewNodeByClass you can use CreateNewNodeByClass. See complete example: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Set_all_slice_views_linked_by_default

1 Like

Thanks, that solved the issue!

1 Like

the example in https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Set_all_slice_views_linked_by_default
contradicts the memory management in https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MemoryManagement

it says that after slicer.mrmlScene.GetNodesByClass it must follow an unregister call.

nodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLinearTransformNode')
nodes.UnRegister(slicer.mrmlScene)  # reference count is increased by both the factory method and the python reference; unregister to keep only the python reference
...

if I do

nodes = slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode")
nodes.UnRegister(slicer.mrmlScene)

Then Slicer complains as AttributeError: 'list' object has no attribute 'UnRegister'

Why does the linked views example works? What is the correct way then?

One method returns a Python list, the other returns a VTK collection.

For Python scripts, it is simpler to use slicer.util.getNodesByClass because it returns a Python list, which is easier to iterate through and UnRegister has been already called internally.

2 Likes