Difference between revisions of "Documentation/Nightly/Developers/FAQ"

From Slicer Wiki
Jump to: navigation, search
m
Tag: 2017 source edit
 
(4 intermediate revisions by the same user not shown)
Line 3: Line 3:
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/General|General}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/General|General}}
 +
 +
{{:Documentation/{{documentation/version}}/Developers/FAQ/WritingDocumentation|Writing Documentation}}
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Building|Building}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Building|Building}}
Line 9: Line 11:
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Debugging|Debugging}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Debugging|Debugging}}
 +
 +
{{:Documentation/{{documentation/version}}/Developers/FAQ/Testing|Testing}}
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Python Scripting|Python Scripting}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Python Scripting|Python Scripting}}
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/MRML|MRML}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/MRML|MRML}}
 +
 +
{{:Documentation/{{documentation/version}}/Developers/FAQ/IO|IO}}
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Modules|Modules}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Modules|Modules}}
 +
 +
{{:Documentation/{{documentation/version}}/Developers/FAQ/SlicerExecutionModel|SlicerExecutionModel}}
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Extensions|Extensions}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Extensions|Extensions}}
Line 21: Line 29:
  
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Device Interoperability|Device interoperability}}
 
{{:Documentation/{{documentation/version}}/Developers/FAQ/Device Interoperability|Device interoperability}}
 +
 +
{{:Documentation/{{documentation/version}}/Developers/FAQ/SVNtoGitHub|SVN to GitHub}}

Latest revision as of 20:51, 12 March 2020

Home < Documentation < Nightly < Developers < FAQ


For the latest Slicer documentation, visit the read-the-docs.


Contents


Developer FAQ: General

What is Slicer ?

3D Slicer is a free open source extensible software application for medical image computing and visualization. Mainly written in C++ and based on the NA-MIC kit, 3D Slicer relies on a variety of libraries: VTK, ITK, CTK, CMake, Qt and Python.

To ensure the stability of the application, relying on a robust software process, the source code is compiled and tested on a daily basis on a variety of platform configurations. The testing results are summarized and reported using a web-based centralized CDash dashboard. Developers of 3D Slicer can also report issues on the Slicer Discourse Forum or using the issues tracker.

3D Slicer consists of both a lean application core and modules offering specific functionality. The core implements the user interface, provides support for data input/output (IO) and visualization and also exposes developer interfaces that support extension of the application with new modules.

Multiple types of modules are supported: CLI, Loadable module, Scripted module and Editor effect. While the developer has to choose between one of these types to implement its module, the end user won't notice the difference as they all share the same look & feel. The choice for a given type of module is usually based on the type of inputs/parameters for a given module.

These modules can be either built-in or installed on demand via the extensions manager.

How can I get help debugging my code?

You can post questions to the developer mailing list.

Please consider:

  • Review the mailing list archives for similar questions
  • If you ask a coding question, try to use a Short Self-Contained Correct Example
  • It's a friendly community but people are busy so if you get a terse response don't take it personally :-)

How to setup for Git development ?

See Slicer Setup

How to contribute a patch ?

The following instructions describes the recommended workflow to contribute patch to Slicer code base.

It is assumed that you followed the New community member checklist, have a clone of https://github.com/Slicer/Slicer/ and have setup the development environment as described here.

  1. Create an issue in the tracker setting severity to feature. For example, see issue #1906

    1. For simple changes (e.g typo, ...), this step is optional.
  2. Make sure your clone has a git remote. After forking Slicer repository, replace jcfr with your git login.

    git remote add jcfr git@github.com:jcfr/Slicer.git
    
  3. Create a topic named <issuer_number>-a-descriptive-topic-name. For example:

    git checkout -b 1906-uninstall-extensions-on-restart
    
  4. Fix the code or implement your feature, then commit your change(s)

    1. Make sure to read the Slicer Coding and Commit Style Guide
  5. Publish the topic on your fork

    git push jcfr 1906-uninstall-extensions-on-restart
    
  6. Create a Pull Request and add a note to the issue with a link pointing to your topic. For example, see note 1906#c4578



What is our bug / feature request workflow ?

The following diagram illustrates Slicer issue workflow:

Mantis-workflow.png

Source: Adapted from http://www.warelab.org/blog/?p=24


How to schedule a Developer Hangout ?

See instruction here


Should core feature be implemented in C++ or Python ?

There is no one-size-fits-all answer to this. There are many examples of "core' features of Slicer implemented using a variety of programming languages and techniques.

  • MRML and most Logic operations are in C++, implemented as VTK subclasses
  • the Application and most GUI functionality is in C++, implemented as QWidget subclasses
  • most bundled modules are implemented as "loadable" modules, combining VTK and Qt parent classes
  • many important modules bundled with Slicer are implemented as python scripted modules (LabelStatistics, ExtensionWizard...) or with hybrid C++ and Python solutions (Editor, DICOM, DataProbe...)
  • other "core" features rely on JavaScript and web technologies (Charts, SceneViews, Extension Manager....)

The implementation choice depends heavily on the use case and the best judgement of the people who commit to maintain the code. If you are contributing an extension that you will maintain, you have a lot of flexibility. If you are hoping to pass off your code to others and you expect them to maintain it, then you should carefully follow the example of similar code that is already being maintained so that your code will be a pleasure to work with and not a misfit that causes trouble.


Original comment from Andras Lasso copied from PR#373 discussion.


There are many reasons for implementing Slicer core in C++, we just list here few reasons:

  • C++ rigor and extensive compile-time checks increases the chance of catching errors earlier. C++ enforces many things that in Python are managed by good programming practices (that are not enforced and in general not followed by Slicer developers).
  • C++ memory management is much more explicit, which is more difficult to learn than Python, but allows much better efficiency (you can prevent memory fragmentation, optimize memory reallocations, etc), which is useful for code that may run hundreds of times per second (this code does).
  • There are lots of good examples of solid, fast C++ displayable managers. Python displayable managers are more at the experimental level.
  • Accessibility of Python classes from C++ modules is cumbersome. Accessibility of C++ classes is very convenient from both Python and C++ modules.
  • Some projects don't use Python and don't want to use it (Python brings in huge amount of additional code, which is a problem if you want to minimize the amount of code that goes through regulatory approval)
  • Profiling and optimization of mixed C++/Python code is very difficult (both C++ and Python profilers treat the "other side" as black hole). Since all the rest of the Slicer core is implemented in C++ (with a few small exceptions), it is much easier to implement this in C++, too.


That said, we love Python programming, do it extensively, but implementing Slicer core features in Python has just too many disadvantages.

How to convert between ITK images and Slicer scalar volume nodes?

See discussion and relevant links at http://slicer-devel.65872.n3.nabble.com/Converting-ITK-image-to-Slicer-ScalarVolumeNode-td4035458.html

Steve Pieper's suggested architecture for using ITK code to process Slicer MRML data is as follows:

1) develop an ITK pipeline that implements the desired behavior

2) wrap the pipeline in a high level pure C++ ITK class that exposes the key inputs, output, parameters, and events

3) write a thin CLI wrapper around (2) using the Slicer Execution mode

4a) use the CLI in Slicer as-is

4b) write a scripted module that presents a higher level interface and calls the CLI

4c) if you need more interactivity, write a vtkITK wrapper around (2) that exposes the high level ITK class aspects using VTK conventions; expose this via a scripted or loadable module.

A nice thing about this approach is that (1) through (3) are all highly reusable in different contexts both in and out of Slicer.

Also this path, steps (1) through (4b) all the data types and orientation mappings between itk::Image and vtkMRMLScalarVolumeNode are handled automatically with existing mechanisms. Since the CLI is built as a shared library by default there is no file system overhead, just a few memcpys which is not much different than using the ITK pipeline directly.

Another option is to implement the pipeline in SimpleITK, but adding custom C++ code into the SimpleITK is more complex and I don't think it's even possible to do this as an extension, whereas the path described above is completely compatible with our extension process.

Note that the use case for the code that Raul points to is the opposite case, using a VTK class inside of an ITK pipeline. In this case ITKVtkGlue is very appropriate. The IJKToRAS transforms are not relevant since vtkImageData class does not support orientation and all the operations need to be performed in pixel space.

If CLI route is not suitable for some reason, helper classes are available in SlicerRT that do conversion between itkImage and vtkMRMLScalarVolumeNode initializing IJKtoRAS matrix, see https://github.com/SlicerRt/SlicerRT/blob/master/SlicerRtCommon/SlicerRtCommon.h

What is the difference between Slicer Plot and Chart ?

Slicer currently has two ways of displaying plots: Plot and Chart:

  • Plots: C++ environment based on VTK plots.
    • Advantages:
      • Plots display data stored in tables. Data is synchronized, therefore any data change in a table updates corresponding plots immediately.
      • Interactive capabilities, such as data selection, point editing by click-and-drag.
      • Faster plotting for many points (number of points > 10^5 is not a problem, it is useful for data exploration).
  • Charts: uses a JavaScript library, jqPlot, for the rendering.
    • Advantages: slightly better quality rendering.

Chart infrastructure will be probably deprecated and removed from future versions of Slicer.


Developer FAQ: Writing Documentation

How to reference module or extension documentation hosted on the Slicer wiki ?

The URL including the Nightly namespace should be used.

Good: https://www.slicer.org/wiki/Documentation/Nightly/Modules/GaussianBlurImageFilter Poor: https://www.slicer.org/wiki/Documentation/4.4/Modules/GaussianBlurImageFilter References to documentation hosted on the wiki usually occurs when:

  • writing module or extension description
  • setting the documentation URL in CMakeLists.txt, cpp or python source files.

Rational: This will facilitate maintenance and avoid to update source files after each release.


Developer FAQ: Building

How is organized the Slicer build tree ?

The Slicer build tree has two levels:

  • ~/Projects/Slicer-SuperBuild
  • ~/Projects/Slicer-SuperBuild/Slicer-build

The first level manages all the external dependencies of Slicer (VTK, ITK, Python, ...). The second level is the "traditional" build directory of Slicer.

See Slicer directory structure

What is a clean build ?

Doing a clean build means that

(1) all directories and files in the top-level build directory ~/Projects/Slicer-SuperBuild are removed.

and

(2) you updated your source checkout and have no locally modified files.

What to do if QtSDK installer hangs ?

If QtSDK installer hangs, use -style cleanlooks command line option. For details, see here.

Which minimum version of GLIBC is needed to build Slicer ?

The minimum version of GLIBC required to build Slicer is defined by the minimum version required by the pre-compiler binaries used when building Slicer. In our case, a small pre-compiled executable called the CTK AppLauncher is downloaded and used at configure and build time each time python has to be invoked.

The precompiled CTKAppLauncher imposes the following requirements regarding GLIBC and GLIBCXX libraries installed on your system:

$ strings CTKAppLauncher | ack GLIBC
GLIBC_2.2.5
GLIBCXX_3.4.11
GLIBCXX_3.4.9
GLIBCXX_3.4
GLIBC_2.3.3
GLIBC_2.3.2
GLIBC_2.4
GLIBC_2.3


To check that your system provides the required GLIBCXX and GLIB versions, you could run the following command and check that the requirement of the launcher can be satisfied:

$ strings /usr/lib/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
$ strings /lib/libc.so.6 | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11

What to do if Visual Studio compiler crashes ?

If the compiler crashes on Windows saying "Microsoft C/C++ Compiler Driver has stopped working", then it's most probably due to long build folder paths. To fix this the Slicer build directory should be moved and/or renamed. A typical build folder path is C:\S4D

How to build Slicer with SSL support ?

To build Slicer with SSL support, you need to build (or download) Qt with SSL support and configure Slicer with -DSlicer_USE_PYTHONQT_WITH_OPENSSL:BOOL=ON

Why Qt 4 >= 4.8.5 should be used on Ubuntu 12.04 and above ?

See Slicer issue #3325

Why distributed CMake can not be used on Ubuntu 12.04 and above ?

What is the ITKFactoryRegistration library ?

The ITKFactoryRegistration library ensures that no duplicated ITK IO factories are registered when CLI shared library modules are loaded. See Slicer issue #2813

Indeed, when ITKv4 is build shared, the library holding the factory registration code are build statically. As a consequence, when CLI modules are loaded as library the factory are registered multiple times. More than 800 factories were registered and this was leading to poor performance when loading images.

The introduction of a shared library named ITKFactoryRegistration (see r21592) that should be linked against to ensure loading of the factories is performed once. This approach requires user of ITK libraries to explicitly set the ITK variable ITK_NO_IO_FACTORY_REGISTER_MANAGER to 1 before calling include(${ITK_USE_FILE}).

Notes:

  • Since calling include(${Slicer_USE_FILE}) already set ITK_NO_IO_FACTORY_REGISTER_MANAGER in the current scope, explicitly setting the variable afterward is not required.

How to configure network proxy ?

As explained here, proxy configured by setting http_proxy and https_proxy environment variables will automatically be used by CMake.


Developer FAQ: Installing

Why building the 'install' target fail ?

Building the install target is not supported and is only used internally by the build system while generating the Slicer package. See Slicer packaging instructions


Developer FAQ: Debugging

How to print QString using GDB ?

See http://silmor.de/qtstuff.printqstring.php

More troubleshooting questions ?

See Troubleshooting


Developer FAQ: Testing

What is the difference between add_test, simple_test, slicer_add_python_test, and slicer_add_python_unittest CMake macros/functions ?

  • add_test: provided by CMake and allows to add a test that can be executed using ctest.
  • simple_test(testname):
    • Usually called after configuring a test driver using SlicerMacroConfigureModuleCxxTestDriver.
    • Accept the same arguments as add_test.
    • Conveniently call ExternalData_add_test with the appropriate parameters.
    • Set the LABELS test property.
    • Invoke test driver using ${Slicer_LAUNCH_COMMAND}
  • slicer_add_python_unittest(SCRIPT script [TESTNAME_PREFIX prefix] [SLICER_ARGS slicer_arg1 [slicer_arg2 [...]]]):
    • Run unittests with Slicer using --python-code "import slicer.testing\\; slicer.testing.runUnitTest(['${CMAKE_CURRENT_BINARY_DIR}', '${_script_source_dir}'], '${test_name}')".
    • Slicer arguments systematically passed are --testing and --no-splash.
    • Conveniently call ExternalData_add_test with the appropriate parameters.
  • slicer_add_python_test(SCRIPT script [TESTNAME_PREFIX prefix] [SLICER_ARGS slicer_arg1 [slicer_arg2 [...]]] [SCRIPT_ARGS script_arg1 [script_arg2 [..]]]):
    • Useful to run a python test that can not be added as a unittest.
    • Run Slicer with the given script.
    • Slicer arguments systematically passed are --testing and --no-splash.
    • Conveniently call ExternalData_add_test with the appropriate parameters.

What is the meaning of prefix py_ in test name ?

It means that the test is implemented in python.


Developer FAQ: Python Scripting

How to run pip ?

The pip executable is not distributed, instead the following command should be used:

  • from build tree: /path/to/Slicer-SuperBuild/python-install/bin/PythonSlicer -m pip ...
  • from install tree:
 * Linux/MacOS: /path/to/Slicer-X.Y.Z-plat-arch/bin/PythonSlicer -m pip ...
 * Windows: "c:\Program Files\Slicer 4.10.0\bin\PythonSlicer.exe" -m pip ...


See this discussion for more details and background: https://discourse.slicer.org/t/slicer-python-packages-use-and-install/984/29.

How to access a scripted module from python scripts

All slicer modules are accessible in the slicer.modules namespace. For example, sampledata module can be accessed as slicer.modules.sampledata.

To access a module's widget, use widgetRepresentation() method to get the C++ base class and its self() method to get the Python class. For example, slicer.modules.sampledata.widgetRepresentation().self() returns the Python widget object of sampledata module.

How to systematically execute custom python code at startup ?

See https://slicer.readthedocs.io/en/latest/user_guide/settings.html#application-startup-file

How to save an image/volume using python ?

The module slicer.util provides methods allowing to save either a node or an entire scene:

  • saveNode
  • saveScene

For more details see:

Enable or disable compression while saving a volume

While volumes can be accessed in Slicer Python modules as vtkMRMLVolumeNode, compression preference (or any other property for that matter) should be passed to slicer.util.saveNode function. The property will be passed to Slicer's storage node. For compression set the useCompression to 0 or 1. Example script:

properties = {'useCompression': 0}; #do not compress
file_path = os.path.join(case_dir, file_name)
slicer.util.saveNode(node, file_path, properties)

How to assign a volume to a Slice view ?

Assuming the MRHead sample data has been loaded, you could do the following:

red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
red_cn = red_logic.GetSliceCompositeNode()
red_logic.GetSliceCompositeNode().SetBackgroundVolumeID(slicer.util.getNode('MRHead').GetID())

Discussion: http://slicer-devel.65872.n3.nabble.com/Assign-volumes-to-views-tt4028694.html

How to access vtkRenderer in Slicer 3D view ?

renderer = slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().GetRenderers().GetFirstRenderer()

How to get VTK rendering backend ?

backend = slicer.app.layoutManager().threeDWidget(0).threeDView().renderWindow().GetRenderingBackend()

How to access displayable manager associated with a Slicer 2D or 3D view ?

As originally explained here, you could use the method getDisplayableManagers() available in any qMRMLThreeDView and qMRMLSliceView.

lm = slicer.app.layoutManager()
for v in range(lm.threeDViewCount):
  td = lm.threeDWidget(v)
  ms = vtk.vtkCollection()
  td.getDisplayableManagers(ms)
  for i in range(ms.GetNumberOfItems()):
   m = ms.GetItemAsObject(i)
   if m.GetClassName() == "vtkMRMLModelDisplayableManager":
     print(m)

How to center the 3D view on the scene ?

layoutManager = slicer.app.layoutManager()
threeDWidget = layoutManager.threeDWidget(0)
threeDView = threeDWidget.threeDView()
threeDView.resetFocalPoint()

Should I use 'old style' or 'new style' python classes in my scripted module ?

When python classes have no superclass specified they are 'old style' as described here [1].

In general it doesn't matter for the classes in a scripted module, since they won't be subclassed either old or new style should be the same.

For other python code in slicer where you might be subclassing, it's better to use new style classes. See the class hierarchies in the EditorLib and the DICOMLib for examples.

How to harden a transform ?

>>> n = getNode('Bone')
>>> logic = slicer.vtkSlicerTransformLogic()
>>> logic.hardenTransform(n)

Discussion: http://slicer-devel.65872.n3.nabble.com/Scripting-hardened-transforms-tt4029456.html

Where can I find example scripts?

Have a look at the Script repository.

How can I use a visual debugger for step-by-step debugging

Visual debugging (setting breakpoints, execute code step-by-step, view variables, stack, etc.) of Python scripted module is possible by using various IDEs. See detailed setup instructions here.

Why can't I access my C++ Qt class from python

  • Python wrapping of a Qt class requires a Qt style constructor with QObject as argument (it can be defaulted to null though), which is public. If one of these are missing, python wrapping will fail for that class
  • You cannot access your custom C++ Qt classes from python outside of the scope of your instantiated python class. These will not work:
BarIDRole = slicer.qFooItemDelegate.LastRole + 1

class BarTableWidget(qt.QTableWidget, VTKObservationMixin):

    def __init__(self, *args, **kwargs):
        [...]
class BarTableWidget(qt.QTableWidget, VTKObservationMixin):

    BarIDRole = slicer.qFooItemDelegate.LastRole + 1

    def __init__(self, *args, **kwargs):
        [...]

Instead, do:

class BarTableWidget(qt.QTableWidget, VTKObservationMixin):

    def __init__(self, *args, **kwargs):
        self.BarIDRole = slicer.qFooItemDelegate.LastRole + 1
        [...]
  • [Other reasons go here]

Can I use factory method like CreateNodeByClass or GetNodesByClass ?

See https://slicer.readthedocs.io/en/latest/developer_guide/advanced_topics.html#memory-management

How can I access callData argument in a VTK object observer callback function

To get notification about an event emitted by a VTK object you can simply use the AddObserver method, for example:

def sceneModifiedCallback(caller, eventId):
  print("Scene modified")
  print("There are {0} nodes in the scene". format(slicer.mrmlScene.GetNumberOfNodes()))

sceneModifiedObserverTag = slicer.mrmlScene.AddObserver(vtk.vtkCommand.ModifiedEvent, sceneModifiedCallback)

If an event also contains additional information as CallData then the type of this argument has to be specified as well, for example:

@vtk.calldata_type(vtk.VTK_OBJECT)
def nodeAddedCallback(caller, eventId, callData):
  print("Node added")
  print("New node: {0}".format(callData.GetName()))

nodeAddedModifiedObserverTag = slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, nodeAddedCallback)

Note: @vtk.calldata_type is a Python decorator, which modifies properties of a function that is declared right after the decorator. The decorator is defined in VTK (in Wrapping\Python\vtk\util\misc.py).

Note: The available types are listed in Wrapping\Python\vtkmodules\util\vtkConstants.py.

Usage from a class requires an extra step of creating the callback in the class __init__ function, as Python2 by default does some extra wrapping (http://stackoverflow.com/questions/9523370/adding-attributes-to-instance-methods-in-python):

class MyClass:
  def __init__(self):
    from functools import partial
    def nodeAddedCallback(self, caller, eventId, callData):
      print("Node added")
      print("New node: {0}".format(callData.GetName()))
    self.nodeAddedCallback = partial(nodeAddedCallback, self)
    self.nodeAddedCallback.CallDataType = vtk.VTK_OBJECT
  def registerCallbacks(self):
    self.nodeAddedModifiedObserverTag = slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, self.nodeAddedCallback)
  def unregisterCallbacks(self):
    slicer.mrmlScene.RemoveObserver(self.nodeAddedModifiedObserverTag)
        
myObject = MyClass()
myObject.registerCallbacks()

Allowed CallDataType values: VTK_STRING, VTK_OBJECT, VTK_INT, VTK_LONG, VTK_DOUBLE, VTK_FLOAT, "string0". See more information here: https://github.com/Kitware/VTK/blob/master/Wrapping/PythonCore/vtkPythonCommand.cxx

For a simplified syntax, see #How_to_manage_VTK_object_connections_.3F

How to manage VTK object connections ?

The VTKObservationMixin is a Python mix-in that allows adding a set of methods to a class by inheritance. It includes the following methods defined in Base/Python/slicer/util.py:

  • addObserver
  • hasObserver
  • observer
  • removeObserver
  • removeObservers

The following illustrates how to observe the slicer.vtkMRMLScene.NodeAddedEvent:

from slicer.util import VTKObservationMixin

class MyClass(VTKObservationMixin):
  def __init__(self):
    VTKObservationMixin.__init__(self)
    self.addObserver(slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, self.nodeAddedCallback)
  
  @vtk.calldata_type(vtk.VTK_OBJECT)
  def nodeAddedCallback(self, caller, eventId, callData):
    print("Node added")
    print("New node: {0}".format(callData.GetName()))

myObject = MyClass()

For additional examples of usage, see test_slicer_util_VTKObservationMixin.py

Slicer crashes if I try to access a non-existing item in an array

For example, this code makes Slicer crash:

s = vtk.vtkStringArray()
s.GetValue(0)

This behavior is expected, as all VTK objects are implemented in C++ that offers much faster operation but developers have to take care of addressing only valid array elements, for example by checking the number of elements in the array:

if itemIndex < 0 or itemIndex >= s.GetNumberOfValues()
  raise IndexError("index out of bounds")


How to run CLI module from Python?

See here.

How can I run slicer operations from a batch script?

Slicer --no-main-window --python-script /tmp/test.py

Contents of /tmp/test.py

# use a slicer scripted module logic
from SampleData import SampleDataLogic
SampleDataLogic().downloadMRHead()
head = slicer.util.getNode('MRHead')

# use a vtk class
threshold = vtk.vtkImageThreshold()
threshold.SetInputData(head.GetImageData())
threshold.ThresholdBetween(100, 200)
threshold.SetInValue(255)
threshold.SetOutValue(0)

#  use a slicer-specific C++ class
erode = slicer.vtkImageErode()
erode.SetInputConnection(threshold.GetOutputPort())
erode.SetNeighborTo4()  
erode.Update()          

head.SetAndObserveImageData(erode.GetOutputDataObject(0))

slicer.util.saveNode(head, "/tmp/eroded.nrrd")

exit()

How can I run Slicer on a headless compute node?

Many cluster nodes are installed with minimal linux systems that don't include X servers. X servers, particularly those with hardware acceleration traditionally needed to be installed with root privileges, making it impossible to run applications that rendered using X or OpenGL.

But there is a workaround which allows everything in slicer to work normally so you could even do headless rendering.

You can use a modern version of X that supports running a dummy framebuffer. This can be installed in user mode so you don't even need to have root on the system.

See [2] for details.

There's a thread here with more discussion: [3]

Here is a working example of the approach running on a headless compute node running CTK tests (which also use Qt and VTK)

[4]

How to save user's selection of parameters and nodes in the scene?

It is preferable to save all the parameter values and nodes selections that the user made on the user interface into the MRML scene. This allows the user to load a scene and continue from where he left off. These information can be saved in a slicer.vtkMRMLScriptedModuleNode() node.

For example:

parameterNode=slicer.vtkMRMLScriptedModuleNode()

# Save parameter values and node references to parameter node

alpha = 5.0
beta = "abc"
inputNode = slicer.util.getNode("InputNode")

parameterNode.SetParameter("Alpha",str(alpha))
parameterNode.SetParameter("Beta", beta)
parameterNode.SetNodeReferenceID("InputNode", inputNode.GetID())

# Retrieve parameter values and node references from parameter node

alpha = float(parameterNode.GetParameter("Alpha"))
beta = parameterNode.GetParameter("Beta")
inputNode = parameterNode.GetNodeReference("InputNode")

Scripted module's logic class have a helper function, getParameterNode, which returns a parameter node that is unique for a specific module. The function creates the parameter node if it has not been created yet. By default, the parameter node is a singleton node, which means that there is only a single instance of the node in the scene. If it is preferable to allow multiple instances of the parameter node, set isSingletonParameterNode member of the logic object to False.

How to load a UI file ?

See Documentation/Nightly/Developers/Tutorials/PythonAndUIFile

How to update progress bar in scripted (Python, or other) CLI modules

As detailed in the Execution Model documentation, Slicer parses specifically-formatted XML commands printed on stdout, to allow any out-of-process CLI program to report progress back to the main Slicer application (which will causing the progress bar to update). However, it is very important to note that the output must be flushed after each print statement, or else Slicer will not parse the progress sections until the process ends. See the calls to

sys.stdout.flush()

in the example Python CLI shown below:

#!/usr/bin/env python-real

if __name__ == '__main__':
  import time
  import sys
  
  print("""<filter-start><filter-name>TestFilter</filter-name><filter-comment>ibid</filter-comment></filter-start>""")
  sys.stdout.flush()

  for i in range(0,10):
      print("""<filter-progress>{}</filter-progress>""".format(i/10.0))
      sys.stdout.flush()
      time.sleep(0.5)

  print("""<filter-end><filter-name>TestFilter</filter-name><filter-time>10</filter-time></filter-end>""")
  sys.stdout.flush()

How to display progress bar for CLI module execution in a scripted module

def createProgressDialog(parent=None, value=0, maximum=100, windowTitle="Processing..."):
    import qt # qt.qVersion()
    progressIndicator = qt.QProgressDialog()  #(parent if parent else self.mainWindow())
    progressIndicator.minimumDuration = 0
    progressIndicator.maximum = maximum
    progressIndicator.value = value
    progressIndicator.windowTitle = windowTitle
    return progressIndicator
      

class MyModuleWidget(ScriptedLoadableModuleWidget, VTKObservationMixin):

    def setup(self)
        parametersFormLayout = qt.QFormLayout(myInputCollapsibleButton)
        self.testButton = qt.QPushButton('Test')
        self.testButton.enabled = True
        self.testButton.clicked.connect(self.onTestButton)
        parametersFormLayout.addRow(self.TestButton)
    
    def onTestButton(self):
        myCli = slicer.modules.tmp2cli
        cliNode = None
        myInt = 100
        cliNode = slicer.cli.run(myCli, cliNode, {'myString': 'hello World', 'myInt':100} )
        cliNode.AddObserver('ModifiedEvent', self.onCliModified)
        self.progressBar = myUtil.createProgressDialog(None, 0, myInt)
    
    def onCliModified(self, caller, event):
        self.progressBar.setValue(caller.GetProgress())
        if caller.GetStatus() == slicer.vtkMRMLCommandLineModuleNode.Completed: 
            self.progressBar.close()

See complete example here.

How to run Python script using a non-Slicer Python environment

If you need to run Python scripts using not Slicer's embedded interpreter but using a different environment (Python3, Anaconda, etc.) then you need to run the Python executable using a default startup environment. Starting from Slicer's environment would cause loading of Slicer's Python libraries, which are expected to be binary incompatible with the external environment and therefore would make the external application crash.

Example of running python code using system Python3 in Linux from Slicer:

command_line = ["/usr/bin/python3", "-c", "print('hola')"]
from subprocess import check_output
command_result = check_output(command_line, env=slicer.util.startupEnvironment())
print(command_result)

This example script just prints 'hola' and exits, but the code can be replaced by more complex instructions or launching of a Python script.

Example of running python code using Anaconda using environment named 'workspace-gpu' on Windows from Slicer:

command_line = [r"c:\Users\msliv\Miniconda3\envs\workspace-gpu\python.exe", "-c", "print('hola')"]
from subprocess import check_output
command_result = check_output(command_line, env=slicer.util.startupEnvironment())
print(command_result)

How to configure network proxy ?

When using either urllib.request or requests, proxy configured by setting http_proxy and https_proxy environment variables will automatically be used.

For more details:


Developer FAQ: MRML

How to add a MRML node into the scene ?

  • Generic pattern
vtkNew<vtkMRML???Node> nodeToAdd;
...
mrmlScene->AddNode(nodeToAdd.GetPointer());
  • Add a polydata to the scene
vtkNew<vtkMRMLModelNode> modelNode;
modelNode->SetPolyData(polyData);
mrmlScene->AddNode(modelNode.GetPointer());
  • Load a polyData from file
vtkSlicerModelsLogic* modelsLogic = ...;
//modelsLogic->SetMRMLScene(mrmlScene);
modelsLogic->AddModel(polyDataFileName);

What to do if you get 'No LookupTable was set but number of components in input doesn't match OutputFormat' when loading a MRML scene ?

If you get the following error messages:

ERROR: In /path/to/VTK/Imaging/vtkImageMapToColors.cxx, line 153
vtkImageMapToColors (0x268f190): RequestInformation: No LookupTable was set but number of components in input doesn't match OutputFormat, therefore input can't be passed through!

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

ERROR: In /path/to/VTK/Imaging/vtkImageExtractComponents.cxx, line 239
vtkImageExtractComponents (0x26947e0): Execute: Component 1 is not in input.

[...]

Make sure the colorNodeRef attribute is set on each VolumeDisplay node.

How to change the volumes in the 2D views ?

appLogic = slicer.app.applicationLogic()
selectionNode = appLogic.GetSelectionNode()
selectionNode.SetReferenceActiveVolumeID(bg)
selectionNode.SetReferenceSecondaryVolumeID(fg)
appLogic.PropagateVolumeSelection()

Source: https://github.com/fedorov/ChangeTrackerPy/blob/master/Wizard/Helper.py#L82

How to know the min/max offset of a slice view ?

vtkMRMLSliceNode* redSliceNode = vtkMRMLSliceNode::SafeDownCast( this->GetMRMLScene()->GetNodeByID( "vtkMRMLSliceNodeRed" ));
vtkMRMLSliceLogic* sliceLogic = this->GetMRMLApplicationLogic()->GetSliceLogic( redSliceNode );

double sliceBounds[6] = {0, -1, 0, -1, 0, -1};
sliceLogic->GetLowestVolumeSliceBounds(sliceBounds);
double min = sliceBounds[4];
double max = sliceBounds[5];

Source: https://github.com/Slicer/Slicer/blob/master/Libs/MRML/Widgets/qMRMLSliceControllerWidget.cxx#L1267-L1276


Developer FAQ: IO

Why is my node writer not showing up in the Save dialog ?

You have implemented a loadable module with a new MRML node, its storage node, and the qSlicerNodeWriter needed to save your node on your system file. If the writer is not showing up for your node in the qSlicerSaveDataDialog, it could be one of those following reasons :

  • You need to register your writer in the qSlicerIOManager in qSlicerYourModule::setup().

Example: qSlicerMarkupsModule writer registration


Developer FAQ: Modules

Within a Slicer build-tree, where are Slicer modules located?

Slicer module executables and libraries are located in your main Slicer build directory Slicer-Superbuild/Slicer-build. Refer to Directory Structure description for more details.

How to build module outside of Slicer source tree

Follow developers guide for building modules

How to modify local version of external module

Some Slicer modules (such as OpenIGTLink and OpenIGTLinkIF) are built as External git projects by CMake scripts in the Slicer/SuperBuild directory. The SuperBuild process may refresh from the repository unexpectedly, overwriting any local changes. To avoid this, comment out the git settings in the appropriate external build file while making local edits. For example, in SuperBuild/External_OpenIGTLinkIF.cmake:

     GIT_REPOSITORY "${git_protocol}://github.com/openigtlink/OpenIGTLinkIF.git"
     GIT_TAG "f9b65b1ffd2992862025f3c6ec5fe30e6f5dd395"
     SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}
     # GIT_REPOSITORY "${git_protocol}://github.com/openigtlink/OpenIGTLinkIF.git"
     # GIT_TAG "f9b65b1ffd2992862025f3c6ec5fe30e6f5dd395"
     SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj}

How to call a CLI module from a C++ loadable module?

Discussion: http://slicer-devel.65872.n3.nabble.com/Calling-CLI-module-from-a-C-loadable-module-tt4031930.html

Example: vtkSlicerCropVolumeLogic.cxx#L318-351

How to call a CLI module from command-line?

Example:

   Slicer.exe --launch CastScalarVolume input.mha output.mha

Notes for windows:

  • Full name of the Slicer executable is required (Slicer.exe, not just Slicer)
  • To get help on command-line arguments the CLI module supports, run:
   Slicer.exe --launch CastScalarVolume 2>c:\SomeWriteAbleDirectory\usage.txt


Developer FAQ: SlicerExecutionModel

What facilities are available for third party software to interface with the NA-MIC Kit?

NA-MIC has committed to developing and supporting a generic batch processing interface. This is the Slicer3 Command Line Interface (CLI). The application programming interface (API) for CLI was worked out based on interactions with the community including input from those familiar with LONI, ITK, Python and Matlab software development practices.

We believe this API already supports all the features required by to implement batch processing with BatchMake, the LONI Pipeline, and any other systems that we may want to work with in the future. The Slicer3 Execution Model provides a simple XML-based descriptor for command line arguments for input/output volumes and related parameters.

Which Third Party software has currently been interfaced to the NA-MIC Kit using the CLI?

  • Batchmake (Kitware)
  • Python
  • Matlab

How do I debug my command line module?

See Debugging

How do I specify a Logo?

You need to create a logo.h file (embedding the zipped pixel data as base64 strings in a C source code). There is a utility bundled with kwwidgets that accomplishes this. From a Slicer3 build directory you can do something like this:

./Slicer3 --launch ../Slicer3-lib/KWWidgets-build/bin/KWConvertImageToHeader --base64 --zlib ~/Desktop/bioimagesuite_logo_www.h ~/Desktop/bioimagesuite_logo_www.png

The resulting .h header file can then be used as an argument to the 'generateclp' cmake macro like this:

generateclp(${CLP}_SOURCE ${CLP}.xml ${Slicer3_SOURCE_DIR}/Resources/bioimagesuite_logo_www.h)

Note: logos are limited in size: if your .h file contains a symbol like 'image_bioimagesuite_logo_www' it will work. But if it has several symbols like 'image_bioimagesuite_logo_www_1' 'image_bioimagesuite_logo_www_2' etc then the logo was too large and needs to be downsampled for use.

What do I do if I want to use the CLI outside of slicer?

In general CLI executables will depend on shared libraries provided by Slicer (such as ITKCommon, etc). To be sure your run-time environment resolves to the correct versions, you should always use a form like:

./Slicer --launch <CLI>

or, you can start a shell from which you can run multiple CLI modules. Something like:

./Slicer --launch xterm &

We do not suggest hard-coding the runtime paths into, for example, your .bashrc since this may interfere with other programs and can make it hard to use multiple versions of slicer on the same account.


This page has been moved to read-the-docs.


Developer FAQ: Dashboard

What time the nightly dashboard starts ?

The nightly build are expected to start every day after 3am UTC (22pm EST) and should be available in the morning. If no build error occurred, the latest packages can be downloaded using on of these links:

How can I setup a dashboard ?

See dashboard setup instruction.

Windows: How to prevent "Error reporting UI" dialog from showing up when a program crash ?

Set registry key DontShowUI to 1 (see HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting)

This will prevent Error reporting UI from showing up when a program crash.

macOS: How to prevent the "application quit unexpectedly" dialog from showing up when a tested program crash ?

Option1:

To prevent CrashReporter dialog from showing up when a program crash:

defaults write com.apple.CrashReporter DialogType none

Option2:

To prevent CrashReporter dialog from showing up when a program crash and instead let the problem appear as a notification instead:

defaults write com.apple.CrashReporter UseUNC 1

References:


Developer FAQ: Device interoperability

Can Oculus Rift be used with Slicer ?

Some preliminary integration work has been done. See http://slicer-devel.65872.n3.nabble.com/Oculus-Rift-td4032779.html

Can Oculus Rift be connected with Slicer through OpenIGTLink ?

Oculus requires very tight integration with the rendering pipeline, so probably the current approach of using a C++ loadable module that directly communicates with the Oculus SDK to get pose and send images is better than going through OpenIGTLink.

Source: http://slicer-devel.65872.n3.nabble.com/OpenIGT-and-Slicer-tp4032868p4032875.html


Developer FAQ: SVN to GitHub

What happen to the existing Slicer GitHub repository ?

Between 2011 and March 2020, Slicer sources were maintained in a SVN repository automatically mirrored on GitHub. To speedup time required to checkout Slicer source code, large data files have been removed from the Slicer commit history.

To ensure existing references to both Git SHA and Pull Requests are reachable, the mirrored GitHub repository has been renamed to https://github.com/Slicer/SlicerGitSVNArchive

Where are the data files removed from the filtered history ?

Before filtering the history, we made sure all large data files were effectively removed from the latest version and downloaded using either ExternalData CMake module or SampleData Slicer module.

For older version, each commit introducing large files has been updated by removing the large files and updating the file GIT_MIGRATION_DATA_REMOVED.txt by listing the corresponding SHA256 and file paths.

Corresponding files have been uploaded as release assets named <filename>_<sha256>. See https://github.com/Slicer/SlicerGitMigrationDataRemoved/releases


What is the SlicerGitSVNArchive repository ?

This corresponds to the original GitHub repository that was a mirror of the Slicer SVN authoritative repository. The former Slicer/Slicer repository was renamed into Slicer/SlicerGitSVNArchive

What happen to the SVN repository ?

Until September 2020, SVN server http://svn.slicer.org hosting the Dart, NAMICSandBox, Slicer3, Slicer3-lib-mirrors and Slicer4 repositories will remain available.

The web server http://viewvc.slicer.org/ will be converted into a static html website.

What happen to the Mantis issue tracker ?

Mantis issue tracker has been retired and new issues should be created here: https://github.com/Slicer/Slicer/issues

For every mantis issues, a GitHub issue has been created with a link to the retired mantis tracker.

To support this, the following redirections have been established:

Slicer4 project has been disabled in Mantis. This means that no issues will be visible on the main page and that user will not be able to create issues in mantis.

How to update the forked origin of your online Slicer fork ?

Following the rename of Slicer to SlicerGitSVNArchive, existing GitHub fork are referencing the "incorrect" repository:

Slicer-fork-reference-SlicerGitSVNArchive.png

To address this, you may delete your fork and re-fork https://github.com/Slicer/Slicer

If there are branches published on your fork that you would like to keep, you have two options:

  • before deleting your online fork, clone your Slicer fork locally so that you could rebase and re-publish your branches
  • rename your Slicer fork to SlicerGitSVNArchive (this should be instead of deleting your online fork)

How to update existing Slicer custom application ?

To ensure Slicer sources can be checked out using the provided Git SHA, in CMakeLists.txt file, replace lines like:

 GIT_REPOSITORY git://github.com/Slicer/Slicer

with

 GIT_REPOSITORY git://github.com/Slicer/SlicerGitSVNArchive