How to show/hide volume node from python script

Hi,
I’m trying to create a node from numpy array as shown below:

nodeName = “NewVolumeNode”
voxelType=vtk.VTK_UNSIGNED_CHAR
imageOrigin = [0.0, 0.0, 0.0]
imageSpacing = [1.0, 1.0, 1.0]
imageDirections = [[1,0,0], [0,1,0], [0,0,1]]

data_vtk = vtk.util.numpy_support.numpy_to_vtk(num_array = imgdata.ravel(), deep = True, array_type = vtk.VTK_FLOAT)
imageData = vtk.vtkImageData()
imageData.SetDimensions(imgdata.shape[::-1])
imageData.GetPointData().SetScalars(data_vtk)

volumeNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLScalarVolumeNode”, nodeName)
volumeNode.SetOrigin(imageOrigin)
volumeNode.SetSpacing(imageSpacing)
volumeNode.SetIJKToRASDirections(imageDirections)
volumeNode.SetAndObserveImageData(imageData)
volumeNode.CreateDefaultDisplayNodes()
volumeNode.CreateDefaultStorageNode()

However, I didn’t find a way on the wiki or other posts to toggle the volume node show/hidden button under Data/Subject Hierachy/Node. I tried:

volumeNode.GetDisplayNode().SetVisibility(True)

But it didn’t work, and I have to toggle the show/hidden manually in slicer UI under Data/Subject Hierachy/Node. Is there any python command to do this? Thanks!

1 Like

The following code will make the ‘volumeNode’ volume appear in the slice windows:

slicer.util.setSliceViewerLayers(background = volumeNode)

and this code will reset the slice windows to be centred on the new volume:

slicer.util.resetSliceViews()

This should effectively do the same thing as toggling the show hide button on the volume in the data module.

1 Like

This works great, thanks!

Sorry I have one follow-up question… I found it is not quite the same thing as toggling the show/hide button. For example, I was trying to load a 2D ultrasound image (volume size=[1,480,640]) and apply transformation on the image. After initial loading, I did

usImgTransformNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLTransformNode”, “TrackedUSImagePose”)
usImgNode.SetAndObserveTransformNodeID(usImgTransformNode.GetID())
and do slicer.util.resetSliceViews() I got:
Image 003
Then I fill in the transformation node with actual matrix by usImgTransformNode.SetMatrixTransformToParent(transformMatrix) and do slicer.util.resetSliceViews(), I got:
Image 005
which is not showing the correct reformatted slice aligned with the volume. However, if I first hide the by clicking the hide button in Data widget
Image 006
and re-click the show button, I have:
Image 007
which is the display I’d like to have. I wonder is there a mechanism behind the show/hide button that I can do with script to enable this kind of behavior? I essentially would like to change the transformation matrice multiple times and show the US image moving in 3D as well as showing the image in one of the slice view.
Thanks!

I am not really sure what is going on there as my slicer program does not have that same behaviour although I am using an older version (4.11.20200930)

Usually the red, yellow and green slice views just look along the primary axes, e.g. the red slice always looks normal to the Sup/Inf axis. It looks like when you pressed the show hide button that the yellow view has become reformatted to look at the rotated volume. As I said my slicer does not reformat the slice views by toggling the show hide button so I am not sure why yours does this?

Anyway if you want some code which is equivalent to pressing the " Rotate to volume plane" button which reformats the slice views to look at the rotated volume try this:

layoutManager = slicer.app.layoutManager()
sliceWidget = layoutManager.sliceWidget('Red')
controller = sliceWidget.sliceController()
controller.rotateSliceToBackground()
slicer.util.resetSliceViews()

This just rotates the red slice to the volume. Just replace the ‘Red’ with ‘Yellow’ or ‘Green’ if you want to rotate the other slices. If you want to rotate all 3 then you will need to loop through them:

layoutManager = slicer.app.layoutManager()
for sliceViewName in layoutManager.sliceViewNames():
    sliceWidget = layoutManager.sliceWidget(sliceViewName)
    controller = sliceWidget.sliceController()
    controller.rotateSliceToBackground()


slicer.util.resetSliceViews()
1 Like

Thanks! I am using the latest stable version (4.11.20210226, revision 29738, built 2021-03-01), and I found that currently there is an attribute error when doing

controller.rotateSliceToBackground()
AttributeError: qMRMLSliceControllerWidget has no attribute named ‘rotateSliceToBackground’

I think now it has been updated to controller.rotateSliceToLowestVolumeAxes() which works great.

1 Like