Issue displaying color legend in other slice views

I was trying to display a color legend in some custom slice views when I noticed that it was not showing as I expected. Is there a certain set of conditions to make sure the color legend shows in the other non-standard slice views.

I start Slicer 5.2.1 (and latest Slicer Preview 5.3.0-2023-02-10), set layout to Four-Up, close Slicer, restart Slicer then run the below snippet

slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutThreeOverThreeView)

import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
mrHead = sampleDataLogic.downloadMRHead()

color_legend_display_node = slicer.modules.colors.logic().AddDefaultColorLegendDisplayNode(mrHead)
color_legend_display_node.SetVisibility(True)

I observe the following where the color legend is showing in the Red/Yellow/Green slice views, but not in the Red+/Yellow+/Green+ slice views.

Then if I close Slicer so that it remembers the “Three over three” layout, relaunch Slicer and run the same script I observe the following where the color legend is showing in all the slice views as I would expect:

@Mik, since you did some of the recent color legend rework, do you know what is going on here?

Definitely a bug. SliceCompositeNode is invalid for a new slice views in color legend displayable manager.

For a fast fix:

  1. Enable Toggle slice visibility in 3D view in slice controller widget
    or
  2. Python script below
layoutManager = slicer.app.layoutManager()
layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutThreeOverThreeView)
import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
mrHead = sampleDataLogic.downloadMRHead()

for sliceViewName in layoutManager.sliceViewNames():
  view = layoutManager.sliceWidget(sliceViewName).sliceView()
  sliceNode = view.mrmlSliceNode()
  sliceLogic = slicer.app.applicationLogic().GetSliceLogic(sliceNode)
  sliceLogic.StartSliceNodeInteraction(slicer.vtkMRMLSliceNode.SliceVisibleFlag)
  sliceNode.SetSliceVisible(True)
  sliceLogic.EndSliceNodeInteraction()

color_legend_display_node = slicer.modules.colors.logic().AddDefaultColorLegendDisplayNode(mrHead)
color_legend_display_node.SetVisibility(True)

After that the color legends are visible and available for editing.
I hope it helps.

I assume then that this commit is likely the culprit for requiring slice visibility to be on?

Quite possible. I haven’t tested color legends with nonstandard slice views.

Issue now being tracked at:

@Mik It would be great if you could try to fix this. I’ve added a comment to the issue about potential approaches.

Fix is ready to review and tests.

Is it possible to update displayable manager data using data from other displayable manager? When we create a non standard slice view and displayable manager for that view we must somehow to get color legend actors from already displayed views (for example from Red slice). Since a newly created slice views don’t have such data.

In general, no. Displayable managers should be kept independent to keep the overall complexity of the application manageable.

What do you mean by “non-standard”?

Why would you need to get the color legend actors?
And why would you need to get any information from other displayable managers instead of getting information directly from the MRML scene content? If there is some logic that you don’t want to repeat in multiple displayable managers then that logic can be moved to somewhere the displayable managers can all access it (in MRML display node, MRML logic classes, etc.).

Non-standard (initial) slice views are any slice views created after already displayed color legend.

For example in script

slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpView)

import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
mrHead = sampleDataLogic.downloadMRHead()

clDisplayNode = slicer.modules.colors.logic().AddDefaultColorLegendDisplayNode(mrHead)
slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutThreeOverThreeView)

Standard slice views are: Red, Green, Yellow
Non standard slice views are: Red+, Green+, Yellow+,

When we try to display a volume for a non standard slice views the color legend is invisible, because color legend display node and actors were created before these non standard slice views.

for color in ["Red+", "Yellow+"]:
    slicer.app.layoutManager().sliceWidget(color).sliceLogic().GetSliceCompositeNode().SetForegroundVolumeID(mrHead.GetID())

The size of the ColorLegendActorsMap is zero for ColorLegendDisplayableManagers in these newly created slice views.

In order to display color legend we must iether recreate ColorLegendDisplayNode or process ColorLegendDisplayNodes from the scene in some logic or in the displayable manager itself.