Synchronize display scale across slice viewers

Hi,
is there a quick way to synchronize the zoom factor across slice viewers?
Thanks
Stephan

Yes. Long-click on slice view link icon and enable hot-linking. Maybe it only synchronizes views that have the same orientation. If this is the case then you may need to write a few-line Python script that observes zoom factor changes in slice views and adjusts zoom factor in all the others.

Hi Andras,

Yes, that is correct.

Unfortunately, this is literally the first time ever I opened the Python interactor. But at least, some googling brought me this far, and it does what I want it to

redSlice = slicer.app.layoutManager().sliceWidget('Red').mrmlSliceNode()
yellowSlice = slicer.app.layoutManager().sliceWidget('Yellow').mrmlSliceNode()

redFOV = redSlice.GetFieldOfView()
yellowSlice.SetFieldOfView(redFOV[0], redFOV[1], redFOV[2])

However, it would be nice to not always have to call the zoom alignment manually. Is there some zoom change event to hook an observer to (in vtkCommand I could not find something that looked very promising, but maybe I just missed it)?

Thank you
Stephan

Nice work! I’ve extended your example with slice node observers, which update field of view in all other slice nodes automatically when a slice node is changed: see complete script here.

2 Likes

Great, thank you @lassoan . That’s exactly what I was looking for.

I just added a tiny bit of additional functionality, namely to toggle zoomSync on and off.

slicer.updatingSliceNodes = False
slicer.zoomSync = False

slicer.sliceNodes = [slicer.app.layoutManager().sliceWidget(viewName).mrmlSliceNode()
    for viewName in slicer.app.layoutManager().sliceViewNames()]

def sliceModified(caller, event):
    if slicer.updatingSliceNodes:
        # prevent infinite loop of slice node updates triggering slice node updates
        return
    slicer.updatingSliceNodes = True
    fov = caller.GetFieldOfView()
    for sliceNode in slicer.sliceNodes:
        if sliceNode != caller:
            sliceNode.SetFieldOfView(*fov)
    slicer.updatingSliceNodes = False

def toggleZoomSync():
    if slicer.zoomSync: 
        # zoom sync is on already, therefore observer function is alread hooked, should be unhooked
        for sliceNode in slicer.sliceNodes:
            sliceNode.RemoveObserver(sliceNode.zoomChangeObserverTag)
        slicer.zoomSync = False
    else: 
        # zoom sync is off --> toogle to on (register observer function)
        for sliceNode in slicer.sliceNodes:
            sliceNode.zoomChangeObserverTag = sliceNode.AddObserver(vtk.vtkCommand.ModifiedEvent, sliceModified)
        slicer.zoomSync = True

toggleZoomSync()

After running this code snippet once, calls to

toggleZoomSync()

toggle slice zoom synchronization on/off.

1 Like