Hi Oliver,
There have been some improvements since 4.8.1 that makes it easier for us to do this. So if you use the latest nightly, then this is what you can do:
Easier setup of volume rendering (no need to create the display node and update it from the logic):
volRenLogic = slicer.modules.volumerendering.logic()
displayNode = volRenLogic.CreateDefaultVolumeRenderingNodes(volumeNode)
This is not very clean, because it uses widgets from the volume rendering module, but you can apply a shift like this:
volRenWidget = slicer.modules.volumerendering.widgetRepresentation()
if volRenWidget is None:
logging.error('Failed to access volume rendering module')
return
# Make sure the proper volume property node is set
volumePropertyNode = displayNode.GetVolumePropertyNode()
if volumePropertyNode is None:
logging.error('Failed to access volume properties')
return
volumePropertyNodeWidget = slicer.util.findChild(volRenWidget, 'VolumePropertyNodeWidget')
volumePropertyNodeWidget.setMRMLVolumePropertyNode(volumePropertyNode)
# Adjust the transfer function
volumePropertyNodeWidget.moveAllPoints(x, 0, false)
where ‘x’ is your shift.
It would be probably possible to do this on the MRML/VTK level, but as there are CTK widget calls involved in moveAllPoints, it is not as easy as it should be, and it was not too high on the priority list thus far.
Hope this helps, let us know if you have further questions.