Skip to content

Python interactor

Davide Punzo edited this page May 2, 2018 · 41 revisions

The Python interactor is a very useful util to access run-time any 3DSlicer and SlicerAstro classes: MRML nodes, Widgets and Logics (e.g., the data of the fits file are stored in the MRML AstroVolume class). Python script can also be runned by typing on the terminal:

Slicer --python-script example.py

or by copying and pasting the code in the python console of 3DSlicer:

See also:

Install Additional Python packages

3DSlicer and SlicerAstro binaries deliver its own Python environment. The Python version is 2.7.13 and it incorporates the additional packages numpy, astropy, scipy. It is possible to install additional 'pure' python packages from the Python interactor as follow:

import pip 
pip.main(['install', 'package_name'])

3DSlicer Python scripts repository

SlicerAstro Python scripts repository

  • SmoothRenderSaveVideos.py:

    slicer.util.loadVolume("/full_path/galaxy.fits",{"center":True})
    mw = slicer.util.mainWindow()
    ms = mw.moduleSelector()
    # Smooth the datacube
    ms.selectModule('AstroSmoothing')
    smowidget = slicer.modules.astrosmoothing.widgetRepresentation()
    smomrmlpara = smowidget.mrmlAstroSmoothingParametersNode()
    smomrmlpara.SetMode("Manual")
    # only if a GPU is present:
    #smomrmlpara.SetHardware(1)
    smowidget.onApply()
    ms.selectModule('AstroVolume')
    # Setting maximum quality for the rendering
    astrovolumewidget = slicer.modules.astrovolume.widgetRepresentation()
    astrovolumewidget.onCurrentQualityControlChanged(1)
    volumes = slicer.mrmlScene.GetNodesByClass("vtkMRMLAstroVolumeNode")
    volumefiltered = volumes.GetItemAsObject(1)
    smomrmlpara.SetInputVolumeNodeID(volumefiltered.GetID())
    astrovolumewidget.onCurrentQualityControlChanged(1)
    # Create videos 
    ms.selectModule('ScreenCapture')
    screencapturewidget = slicer.modules.screencapture.widgetRepresentation()
    instance = screencapturewidget.self()
    viewNode = slicer.util.getNode('vtkMRMLViewNode1')
    instance.viewNodeSelector.setCurrentNode(viewNode)
    instance.numberOfStepsSliderWidget.setValue(360)
    instance.videoExportCheckBox.setChecked(1)
    instance.videoFormatWidget.setCurrentIndex(1)
    instance.videoFileNameWidget.setText("WEIN069.mp4")
    instance.videoLengthSliderWidget.setValue(6)
    instance.onCaptureButton()
    viewNode = slicer.util.getNode('vtkMRMLViewNode2')
    instance.viewNodeSelector.setCurrentNode(viewNode)
    instance.viewNodeSelector.setCurrentNode(viewNode)
    instance.numberOfStepsSliderWidget.setValue(360)
    instance.videoExportCheckBox.setChecked(1)
    instance.videoFormatWidget.setCurrentIndex(1)
    instance.videoFileNameWidget.setText("WEIN069_smoothed.mp4")
    instance.videoLengthSliderWidget.setValue(6)
    instance.onCaptureButton()
  • Create(alike)MomentMap.py:

    # Get the data-cube volume
    volumeNode = getNode('name of the object')
    datacube = volumeNode.GetImageData()
    
    # Get dimensions
    N1 = int(volumeNode.GetAttribute("SlicerAstro.NAXIS1"))
    N2 = int(volumeNode.GetAttribute("SlicerAstro.NAXIS2"))
    RMS = float(volumeNode.GetAttribute("SlicerAstro.RMS"))
    
    # Create an empty 2-D image
    imageSize = [N1, N2, 1]
    imageSpacing = [1.0, 1.0, 1.0]
    voxelType = vtk.VTK_FLOAT
    imageDataTemp = vtk.vtkImageData()
    imageDataTemp.SetDimensions(imageSize)
    imageDataTemp.SetSpacing(imageSpacing)
    imageDataTemp.AllocateScalars(voxelType, 1)
    
    extentTemp = imageDataTemp.GetExtent()
    for i in xrange(extentTemp[0], extentTemp[1]+1):
        for j in xrange(extentTemp[2], extentTemp[3]+1):
           for k in xrange(extentTemp[4], extentTemp[5]+1):
              imageDataTemp.SetScalarComponentFromFloat(i,j,k,0,0.)
    
    # calculate moment map
    imageData = volumeNode.GetImageData()
    extent = imageData.GetExtent()
    for i in xrange(extent[0], extent[1]+1):
        for j in xrange(extent[2], extent[3]+1):
           sum = 0.
           for k in xrange(extent[4], extent[5]+1):
              value = imageData.GetScalarComponentAsFloat(i,j,k,0)
              if value > 3 * RMS:
                 sum += value
           imageDataTemp.SetScalarComponentFromFloat(i,j,0,0,sum)
    
    imageDataTemp.Modified()
    point = imageDataTemp.GetPointData()
    array = point.GetArray("ImageScalars")
    point.Modified()
    array.Modified()
    array.GetValueRange()
    
    # create Astro Volume for the moment map
    astroVolumeLogic = slicer.modules.astrovolume.logic()
    volumeNodeMomentMap = astroVolumeLogic.CloneVolume(slicer.mrmlScene, volumeNode, 'MomentMap')
    
    # modify fits attributes
    volumeNodeMomentMap.SetAttribute("SlicerAstro.NAXIS", "2")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.NAXIS3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.CROTA3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.CRPIX3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.CRVAL3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.CTYPE3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.CUNIT3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.DTYPE3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.DRVAL3")
    volumeNodeMomentMap.RemoveAttribute("SlicerAstro.DUNIT3")
    
    # copy 2-D image into the Astro Volume object
    volumeNodeMomentMap.SetAndObserveImageData(imageDataTemp)
    volumeNodeMomentMap.UpdateNoiseAttributes()
    volumeNodeMomentMap.UpdateRangeAttributes()
    
    # change colorMap of the 2-D image
    displayNode = volumeNodeMomentMap.GetDisplayNode()
    displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeRainbow')
    
    # changing the colorMap parameters
    #displayNode.AutoWindowLevelOff()
    #displayNode.SetWindow(??)
    #displayNode.SetLevel(??)
    
    
    
  • AccessDataAsNumpy.py:

def astroArrayFromVolume(volumeNode):
 """Return voxel array from volume node as numpy array.
 Voxels values are not copied. Voxel values in the volume node can be modified
 by changing values in the numpy array.
 After all modifications has been completed, call volumeNode.Modified().

 .. warning:: Memory area of the returned array is managed by VTK, therefore
   values in the array may be changed, but the array must not be reallocated
   (change array size, shallow-copy content from other array most likely causes
   application crash). To allow arbitrary numpy operations on a volume array:

     1. Make a deep-copy of the returned VTK-managed array using :func:`numpy.copy`.
     2. Perform any computations using the copied array.
     3. Write results back to the image data using :py:meth:`updateVolumeFromArray`.
 """
 scalarTypes = ['vtkMRMLAstroVolumeNode', 'vtkMRMLAstroLabelMapVolumeNode']
 vimage = volumeNode.GetImageData()
 nshape = tuple(reversed(volumeNode.GetImageData().GetDimensions()))
 narray = None
 if volumeNode.GetClassName() in scalarTypes:
   narray = vtk.util.numpy_support.vtk_to_numpy(vimage.GetPointData().GetScalars()).reshape(nshape)
 return narray

def astroUpdateVolumeFromArray(volumeNode, narray):
 """Sets voxels of a volume node from a numpy array.
 Voxels values are deep-copied, therefore if the numpy array
 is modified after calling this method, voxel values in the volume node will not change.
 Dimensions and data size of the source numpy array does not have to match the current
 content of the volume node.
 """

 vshape = tuple(reversed(narray.shape))
 if len(vshape) == 1:
   narray = numpy.expand_dims(narray, axis=0)
   narray = numpy.expand_dims(narray, axis=0)
   vshape = tuple(reversed(narray.shape))
   vcomponents = 1
 elif len(vshape) == 2:
   narray = numpy.expand_dims(narray, axis=0)
   vshape = tuple(reversed(narray.shape))
   vcomponents = 1
 elif len(vshape) == 3:
   vcomponents = 1
 else:
   raise RuntimeError("Unsupported numpy array shape: "+str(narray.shape))

 vimage = volumeNode.GetImageData()
 if vimage is None:
   vimage = vtk.vtkImageData()
   volumeNode.SetAndObserveImageData(vimage)

 vtype = vtk.util.numpy_support.get_vtk_array_type(narray.dtype)
 vimage.SetDimensions(vshape)
 vimage.AllocateScalars(vtype, vcomponents)

 narrayTarget = astroArrayFromVolume(volumeNode)
 narrayTarget[:] = narray

 # Notify the application that image data is changed
 # (same notifications as in vtkMRMLVolumeNode.SetImageDataConnection)
 imageData = volumeNode.GetImageData()
 pointData = imageData.GetPointData() if imageData else None
 if pointData is not None:
   if pointData.GetScalars() is not None:
     pointData.GetScalars().Modified()

 volumeNode.StorableModified()
 volumeNode.Modified()
 volumeNode.InvokeEvent(slicer.vtkMRMLVolumeNode.ImageDataModifiedEvent, volumeNode)
  • maskVolumeWithLabelVolume.py:

    # Get the data-cube volumes
    volumeNode = getNode('Name')
    volumeLabelNode = getNode('LabelName')
    
    # masking
    imageData = volumeNode.GetImageData()
    imageDataLabel = volumeLabelNode.GetImageData()
    extent = imageData.GetExtent()
    for i in xrange(extent[0], extent[1]+1):
       for j in xrange(extent[2], extent[3]+1):
          for k in xrange(extent[4], extent[5]+1):
             if imageDataLabel.GetScalarComponentAsFloat(i,j,k,0) < 1 :
                imageData.SetScalarComponentFromFloat(i,j,k,0, 0.)
    
    # update volume keywords
    volumeNode.UpdateNoiseAttributes()
    volumeNode.UpdateRangeAttributes()
    
    
  • accessSlicerAstrovtkFits.py:

    import vtkFitsPython as vtkFits
    vtkFits.vtkFITSReader()
    dir(vtkFits)
    
    
  • more to come...

Clone this wiki locally