Skip to content

Commit

Permalink
ENH: Color legend rework
Browse files Browse the repository at this point in the history
Color legend (formerly "color bar" or "scalar bar"), which can display scalar (or label) mapping to colors was completely reworked to conform with Slicer architecture. The new implementation is simpler (does not require manual adjustment of number of colors and scalar range, accessible in subject hierarchy and Colors, Volumes, and Markups modules) and safer (less chance for displayed and actual scalar range getting out of sync), and more capable (multiple color legends can be displayed).

A new display node, vtkMRMLColorLegendDisplayNode was added, which is displayed by vtkMRMLColorLegendDisplayableManager. The old vtkMRMLScalarBarDisplayableManager remained unchanged (including the name, which is now not very accurate) for now, for backward compatibility.

A subject hierarchy plugin is added, which adds the "Show color legend" checkbox to the visibility menu (right-click on eye icon in the data tree) to show-hide color legend with default options. Color legend properties can be edited for all nodes in Color module. A Color legend section was added to Volumes, Models, and Markups modules to allow editing of color legend properties without leaving those modules. qMRMLColorLegendDisplayNodeWidget was added to allow editing of color legend properties in custom GUIs.

Additional improvements:
- Unified design of handling of "additional" display nodes (such as volume rendering and color legend display nodes) that should not be automatically displayed when user request show of the displayable node (e.g., clicking on the eye icon). If the new ShowMode property of the display node is be set to ShowIgnore then show/hide requests of the displayable node will not affect visibility of the display node. This is useful because often color legend or volume rendering is disabled explicitly (using the subject hierarchy visibility menu) to prevent clutter in viewers and in these cases the user would not want to show these again when overall visibility is toggled.
- Added Qt designer plugins for Volumes widgets.
- Improved Color module widget layout: If Discrete and Continuous color lookup table are showed in the same collapsible section. This way if the section is collapsed then it remains collapsed regardless of what color node is selected (so the Color legend section position on screen remains the same).
- Improved Volumes module widget layout: Display section used a QStackedWidget-based widget, which always filled the available space, pushing down the Color legend section. Switched to using a simple QWidget and switch between qSlicer*DisplayWidget widgets manually.

Co-authored-by: Andras Lasso <lasso@queensu.ca>
  • Loading branch information
Mikhail Polkovnikov and lassoan committed Jan 14, 2022
1 parent 36c6c72 commit d36e96b
Show file tree
Hide file tree
Showing 98 changed files with 6,398 additions and 1,273 deletions.
55 changes: 55 additions & 0 deletions Docs/developer_guide/modules/colors.md
@@ -0,0 +1,55 @@
# Colors

## Color table file format (.txt, .ctbl)

The color file format can store a [color node](http://apidocs.slicer.org/master/classvtkMRMLColorNode.html) in a plain text file with the `.txt` or `.ctbl` extension. It is a text file with values separated by space, with a custom header to specify lookup table type. Header lines are prefixed with `#`.

### Discrete scale color lookup table

Header starts with `# Color table file`. Each data line contains `color index` (integer), `color name` (string, if the name contains spaces then the spaces must be replaced by underscore), `red` (0-255), `green` (0-255), `blue` (0-255), and `opacity` (0-255).

Example:

```
# Color table file C:/Users/andra/OneDrive/Projects/SlicerTesting2022/20220109-ColorLegend/Segmentation-label_ColorTable.ctbl
# 4 values
0 Background 0 0 0 0
1 artery 216 101 79 255
2 bone 241 214 145 255
3 connective_tissue 111 184 210 255
```

### Continuous scale color lookup table

Header starts with `# Color procedural file`. Each data line contains `position` (mapped value, a floating-point number), `red` (0.0-1.0), `green` (0.0-1.0), `blue` (0.0-1.0).

Example:

```
# Color procedural file /path/to/file.txt
# 5 points
# position R G B
0 0 0 0
63 0 0.501961 0.490196
128 0.501961 0 1
192 1 0.501961 0
255 1 1 1
```

## Debugging

### Access scalar bar actor

Access to the scalar bar VTK actor may can be useful for debugging and for experimenting with new features. This code snippet shows how to access the actor in the Red slice view using Python:

```python
displayableNode = getNode('Model')
colorLegendDisplayNode = slicer.modules.colors.logic().GetColorLegendDisplayNode(displayableNode)
sliceView = slicer.app.layoutManager().sliceWidget('Red').sliceView()
displayableManager = sliceView.displayableManagerByClassName("vtkMRMLColorLegendDisplayableManager")
colorLegendActor = displayableManager.GetColorLegendActor(colorLegendDisplayNode)

# Experimental adjustment of a parameter that is not exposed via the colorLegendDisplayNode
colorLegendActor.SetBarRatio(0.2)
sliceView.forceRender()
```
1 change: 1 addition & 0 deletions Docs/developer_guide/modules/index.md
Expand Up @@ -5,6 +5,7 @@ Modules usually interact with each other only indirectly, by making changes and
```{toctree}
:maxdepth: 2
colors
dicom
markups
segmenteditor
Expand Down
30 changes: 12 additions & 18 deletions Docs/developer_guide/script_repository/gui.md
Expand Up @@ -450,25 +450,22 @@ for i in range(0,255):
slicer.mrmlScene.AddNode(invertedocean)
```

### Show color scalar bar in slice views
### Show color legend for a volume node

Display color bar for background volume in slice views (managed by DataProbe):
Display color legend for a volume node in slice views:

```python
sliceAnnotations = slicer.modules.DataProbeInstance.infoWidget.sliceAnnotations
sliceAnnotations.sliceViewAnnotationsEnabled = True
sliceAnnotations.scalarBarEnabled = 1
sliceAnnotations.scalarBarSelectedLayer = "background" # alternative is "foreground"
sliceAnnotations.rangeLabelFormat = "test %G"
sliceAnnotations.updateSliceViewFromGUI()
volumeNode = getNode('MRHead')
colorLegendDisplayNode = slicer.modules.colors.logic().AddDefaultColorLegendDisplayNode(volumeNode)
```

### Display color scalar bar in 3D views
### Create custom color map and display color legend

```python
modelNode = getNode('MyModel') # color legend requires a displayable node
colorTableRangeMm = 40
title ="Radial\nCompression\n"
labelsFormat = "%4.1f mm"
labelFormat = "%4.1f mm"

# Create color node
colorNode = slicer.mrmlScene.CreateNodeByClass("vtkMRMLProceduralColorNode")
Expand All @@ -489,14 +486,11 @@ colorMap.AddRGBPoint(colorTableRangeMm * 0.2, 0.0, 1.0, 1.0)
colorMap.AddRGBPoint(colorTableRangeMm * 0.5, 1.0, 1.0, 0.0)
colorMap.AddRGBPoint(colorTableRangeMm * 1.0, 1.0, 0.0, 0.0)

# Display color scalar bar
colorWidget = slicer.modules.colors.widgetRepresentation()
colorWidget.setCurrentColorNode(colorNode)
ctkScalarBarWidget = slicer.util.findChildren(colorWidget, name="VTKScalarBar")[0]
ctkScalarBarWidget.setDisplay(1)
ctkScalarBarWidget.setTitle(title)
ctkScalarBarWidget.setMaxNumberOfColors(256)
ctkScalarBarWidget.setLabelsFormat(labelsFormat)
# Display color legend
modelNode.GetDisplayNode().SetAndObserveColorNodeID(colorNode.GetID())
colorLegendDisplayNode = slicer.modules.colors.logic().AddDefaultColorLegendDisplayNode(modelNode)
colorLegendDisplayNode.SetTitleText(title)
colorLegendDisplayNode.SetLabelFormat(labelFormat)
```

### Customize view layout
Expand Down
4 changes: 2 additions & 2 deletions Docs/user_guide/getting_started.md
Expand Up @@ -182,7 +182,7 @@ Terms used in various fields of medical and biomedical image computing and clini
- **Bounds**: Describes bounding box of a spatial object along 3 axes. Defined in VTK by 6 floating-point values: `X_min`, `X_max`, `Y_min`, `Y_max`, `Z_min`, `Z_max`.
-** Brightness/contras**t: Specifies linear mapping of voxel values to brightness of a displayed pixel. Brightness is the linear offset, contrast is the multiplier. In medical imaging, this linear mapping is more commonly specified by window/level values.
- **Cell**: Data cells are simple topological elements of meshes, such as lines, polygons, tetrahedra, etc.
- **Color bar** (or scalar bar): a widget overlaid on slice or 3D views that displays a color bar, indicating mapping between color and data value.
- **Color legend** (or color bar, scalar bar): a widget overlaid on slice or 3D views that displays a color legend, indicating meaning of colors.
- **Coordinate system** (or coordinate frame, reference frame, space): Specified by position of origin, axis directions, and distance unit. All coordinate systems in 3D Slicer are right-handed.
- **Extension** (or Slicer extension): A collection of modules that is not bundled with the core application but can be downloaded and installed using the Extensions manager.
- [**Extensions manager**](extensions_manager): A software component of Slicer that allows browsing, installing, uninstalling extensions in the [Extensions catalog (also known as the Slicer app store)](https://extensions.slicer.org) directly from the application.
Expand Down Expand Up @@ -215,7 +215,7 @@ Terms used in various fields of medical and biomedical image computing and clini
- **Segment** (also known as structure, contour, region of interest): One structure in a segmentation. See more information in [Image segmentation](image_segmentation) section.
- **Segmentation** (also known as contouring, annotation, region of interest, structure set): Process of delineating 3D structures in images. Segmentation can also refer to the MRML node that is the result of the segmentation process. A segmentation node typically contains multiple segments (each segment corresponds to one 3D structure). Segmentation nodes are not labelmap nodes or model nodes but they can store multiple representations (binary labelmap, closed surface, etc.). See more information in [Image segmentation](image_segmentation) section.
- **Slice**: Intersection of a 3D object with a plane.
- **Slice view annotations**: text in corner of slice views displaying name, selected DICOM tags, and color bar of the displayed volumes
- **Slice view annotations**: text in corner of slice views displaying name, and selected DICOM tags of the displayed volumes
- **Spacing**: Voxel size of a volume, typically specified in mm/pixel.
- **Transform** (or transformation): Can transform any 3D object from one coordinate system to another. Most common type is rigid transform, which can change position and orientation of an object. Linear transforms can scale, mirror, shear objects. Non-linear transforms can arbitrarily warp the 3D space. To display a volume in the world coordinate system, the volume has to be resampled, therefore transform *from* the world coordinate system to the volume is needed (it is called the resampling transform). To transform all other node types to the world coordinate system, all points must be transformed *to* the world coordinate system (modeling transform). Since a transform node must be applicable to any nodes, transform nodes can provide both *from* and *to* the parent (store one and compute the other on-the-fly).
- **Volume** (or volume node, scalar volume, image): MRML node storing 3D array of voxels. Indices of the array are typically referred to as IJK. Range of IJK coordinates are called extents. Geometry of the volume is specified by its origin (position of the IJK=(0,0,0) point), spacing (size of a voxel along I, J, K axes), axis directions (direction of I, J, K axes in the reference coordinate system) with respect to a frame of reference. 2D images are single-slice 3D volumes, with their position and orientation specified in 3D space.
Expand Down

0 comments on commit d36e96b

Please sign in to comment.