Observing a change in SliceOffset within a SegmentEditorEffect class

Hello,

I am trying to detect changes in slice offsets e.g. slicer.app.layoutManager().sliceWidget('Red').sliceLogic().GetSliceOffset() and call a method within a SegmentEditorEffect class. I want to use the AddObserver method but I couldn’t find an event to attach to in these classes, even though I think one is there but I don’t know it:

http://apidocs.slicer.org/master/classvtkMRMLSliceLogic.html
http://apidocs.slicer.org/master/classvtkMRMLScene.html
http://apidocs.slicer.org/master/classqMRMLSliceView.html

In general, if you want to get notified about changes in a VTK object, such as a MRML node, add an observer the “modified” event (vtk.vtkCommand.ModifiedEvent).

1 Like

Thank you for that. However, when I try to set a sample method to a sliceLogic node, it executes 6 times when I change the Slice Offset. Here is how to reproduce this:

def sampleMethod(caller, event):
  print("This is a sample method")

color = "Red"
import SampleData
SampleData.SampleDataLogic().downloadMRBrainTumor1()
sliceLogic = slicer.app.layoutManager().sliceWidget(color).sliceLogic()
sliceLogic.AddObserver(vtk.vtkCommand.ModifiedEvent, sampleMethod)
sliceLogic.SetSliceOffset(sliceLogic.GetSliceOffset() + 0.01)

I want it only to execute once when sliceLogic.SetSliceOffset(sliceLogic.GetSliceOffset() + 0.01) is called, how do I achieve this?

This happens because the underlying sliceNode is effectively modified few times.

The preferred way to update the offset is to set property on the node itself. (see below)

Waiting we fix the code to effectively trigger on Modified event, here is a workaround

import SampleData
from slicer.util import NodeModify

SampleData.SampleDataLogic().downloadMRBrainTumor1()

def sampleMethod(caller, event):
  print("This is a sample method")

color = "Red"

sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNode%s" % color)
sliceNode.AddObserver(vtk.vtkCommand.ModifiedEvent, sampleMethod)

with NodeModify(sliceNode):
  sliceNode.SetSliceOffset(sliceNode.GetSliceOffset() + 0.01)

Note also that using the method vtkMRMLSliceLogic::SetSliceOffset provided by the logic is deprecated. I found out by looking at a comment in the implementation, we will need to update the documentation:

1 Like

Note that it is normal t get multiple node Modified events, often because of changing of properties that are not relevant for you, and potentially triggered by other modules.

So, if performance is an issue, then you have many options to deal with this. For example:

  • Option A: Check if relevant properties of the observed node are changed and only perform your lengthy processing if needed (you need to store the properties that you used for the last processing)
  • Option B: Do a delayed update. Instead of calling processing method directly, create a QTimer that calls the processing method when the time is up. When you get a modified event, reset the QTimer. Typically a delay of about 1 second or less works well. This method is used in the Grow from seeds segment editor effect.
1 Like

I did exactly option A, thanks.

Also, jcfr’s method of using the SliceNode’s SetSliceOffset method only calls ModifiedEvent once, which works without having to use a workaround.