def onInputChanged(self): self.__chartTable.SetNumberOfRows(self.numFrames) self.plotFrame.enabled = True # self.plotFrame.collapsed = 0 self.__xArray.SetNumberOfTuples(self.numFrames) self.__xArray.SetNumberOfComponents(1) self.__xArray.Allocate(self.numFrames) self.__xArray.SetName('frame') self.__yArray.SetNumberOfTuples(self.numFrames) self.__yArray.SetNumberOfComponents(1) self.__yArray.Allocate(self.numFrames) self.__yArray.SetName('signal intensity') self.__chartTable = vtk.vtkTable() self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.__chartTable.SetNumberOfRows(self.numFrames) # get the range of intensities for the self.__mvRange = [0, 0] for v in self.nodeImgList[0][0]: frame = v frameRange = frame.GetScalarRange() self.__mvRange[0] = min(self.__mvRange[0], frameRange[0]) self.__mvRange[1] = max(self.__mvRange[1], frameRange[1]) # self.__mvLabels = string.split(self.__mvNode.GetAttribute('MultiVolume.FrameLabels'),',') #if len(self.__mvLabels) != nFrames: # return self.__mvLabels = [] for l in range(self.numFrames): self.__mvLabels.append(float(l))
def updateChart(self): outputTransformSequenceNode = self.outputTransformSequenceSelector.currentNode() self.__chart.RemovePlot(0) if outputTransformSequenceNode == None: return if outputTransformSequenceNode.GetDataNodeClassName() != "vtkMRMLLinearTransformNode": return numOfDataNodes = outputTransformSequenceNode.GetNumberOfDataNodes() indexName = outputTransformSequenceNode.GetIndexName() self.__xArray.SetNumberOfTuples(numOfDataNodes) self.__xArray.SetNumberOfComponents(1) self.__xArray.Allocate(numOfDataNodes) self.__xArray.SetName(indexName) self.__yArray.SetNumberOfTuples(numOfDataNodes) self.__yArray.SetNumberOfComponents(1) self.__yArray.Allocate(numOfDataNodes) self.__yArray.SetName('DisplacementX') self.__zArray.SetNumberOfTuples(numOfDataNodes) self.__zArray.SetNumberOfComponents(1) self.__zArray.Allocate(numOfDataNodes) self.__zArray.SetName('DisplacementY') self.__mArray.SetNumberOfTuples(numOfDataNodes) self.__mArray.SetNumberOfComponents(1) self.__mArray.Allocate(numOfDataNodes) self.__mArray.SetName('DisplacementZ') self.__chartTable = vtk.vtkTable() self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.__chartTable.AddColumn(self.__zArray) self.__chartTable.AddColumn(self.__mArray) self.__chartTable.SetNumberOfRows(numOfDataNodes) for i in range(numOfDataNodes): self.__chartTable.SetValue(i, 0, float(outputTransformSequenceNode.GetNthIndexValue(i))) linearTransformNode = outputTransformSequenceNode.GetNthDataNode(i) vtkMatrix = linearTransformNode.GetTransformToParent().GetMatrix() self.__chartTable.SetValue(i, 1, vtkMatrix.GetElement(0,3)) self.__chartTable.SetValue(i, 2, vtkMatrix.GetElement(1,3)) self.__chartTable.SetValue(i, 3, vtkMatrix.GetElement(2,3)) self.__chart.GetAxis(0).SetTitle('displacement(mm)') self.__chart.GetAxis(1).SetTitle('time(s)') plot = self.__chart.AddPlot(0) if self.chartingDisplayOption == 'LR': plot.SetInput(self.__chartTable, 0, 1) if self.chartingDisplayOption == 'AP': plot.SetInput(self.__chartTable, 0, 2) if self.chartingDisplayOption == 'SI': plot.SetInput(self.__chartTable, 0, 3)
def populateChart(self): # strip elements from 2nd 3d view # and add our own chart renderer to it self.aModeImageNode = slicer.util.getNode('Image_NeedleTip') if self.aModeImageNode is None: logging.debug( "Cannot locate Image_NeedleTip, can't visualize chart") return self.imageData = self.aModeImageNode.GetImageData() if not self.table is None: # We already have created all of the things, don't recreate self.view.GetInteractor().Initialize() self.chart.RecalculateBounds() return self.table = vtk.vtkTable() self.chart = vtk.vtkChartXY() self.line = self.chart.AddPlot(0) self.view = vtk.vtkContextView() self.signalArray = vtk.vtkDoubleArray() self.signalArray.SetName("RF Signal") self.distanceArray = vtk.vtkDoubleArray() self.distanceArray.SetName("Distance (mm)") self.imageDimensions = self.imageData.GetDimensions() self.signalArray.SetNumberOfTuples(self.imageDimensions[0]) self.distanceArray.SetNumberOfTuples(self.imageDimensions[0]) self.table.AddColumn(self.distanceArray) self.table.AddColumn(self.signalArray) self.line = self.chart.AddPlot(0) self.line.SetInputData(self.table, 0, 1) self.line.SetColor(0, 255, 0, 255) self.line.SetWidth(1.0) inc = 1000 * 1480 / ( 2 * 420e6 ) # distance in mm. The delay distance is added to the increments. (2e-6*1480/2) + distanceDelay = 1000 * 2e-6 * 1480 / 2 for i in range(self.imageDimensions[0]): self.distanceArray.SetComponent(i, 0, distanceDelay + inc * i) self.view.GetRenderer().SetBackground(1.0, 1.0, 1.0) self.view.GetRenderWindow().SetSize(400, 300) # self.contextScene = vtk.vtkContextScene() # self.contextScene.AddItem(self.chart) # self.contextActor = vtk.vtkContextActor() self.view.GetScene().AddItem(self.chart) self.view.GetRenderWindow().SetMultiSamples(0) # self.layoutManager.threeDWidget(1).threeDView.renderWindow().GetRenderer().GetFirstRenderer().AddActor(self.contextActor) self.view.GetInteractor().Initialize()
def CalculatePlane( self, inPoints, base, dir1, dir2, normal ): # Create arrays for the dataset points2D = vtk.vtkPoints() arrayX = vtk.vtkDoubleArray() arrayX.SetNumberOfComponents( 1 ) arrayX.SetName ( 'X' ) arrayY = vtk.vtkDoubleArray() arrayY.SetNumberOfComponents( 1 ) arrayY.SetName ( 'Y' ) arrayZ = vtk.vtkDoubleArray() arrayZ.SetNumberOfComponents( 1 ) arrayZ.SetName ( 'Z' ) # Add the points to the table for i in range( 0, inPoints.GetNumberOfPoints() ): currPoint = [ 0, 0, 0 ] inPoints.GetPoint( i, currPoint ) arrayX.InsertNextValue( currPoint[ 0 ] ) arrayY.InsertNextValue( currPoint[ 1 ] ) arrayZ.InsertNextValue( currPoint[ 2 ] ) # Create a table for the dataset table = vtk.vtkTable() table.AddColumn( arrayX ) table.AddColumn( arrayY ) table.AddColumn( arrayZ ) # Setting up the PCA pca = vtk.vtkPCAStatistics() pca.SetInputData( vtk.vtkStatisticsAlgorithm.INPUT_DATA, table ) pca.SetColumnStatus( 'X', 1 ) pca.SetColumnStatus( 'Y', 1 ) pca.SetColumnStatus( 'Z', 1 ) pca.RequestSelectedColumns() pca.SetDeriveOption( True ) pca.Update() eigvec = vtk.vtkDoubleArray() pca.GetEigenvectors( eigvec ) eigvec.GetTuple( 0, dir1 ) eigvec.GetTuple( 1, dir2 ) eigvec.GetTuple( 2, normal ) mean = self.CalculateMean( inPoints ) base[0] = mean[0] base[1] = mean[1] base[2] = mean[2]
def onInputChanged(self): self.__mvNode = self.__mvSelector.currentNode() if self.__mvNode != None: Helper.SetBgFgVolumes(self.__mvNode.GetID(), None) nFrames = self.__mvNode.GetNumberOfFrames() self.__mdSlider.minimum = 0 self.__mdSlider.maximum = nFrames - 1 self.__chartTable.SetNumberOfRows(nFrames) # if self.__cvn != None: # self.__cvn.SetChartNodeID(self.__cn.GetID()) self.ctrlFrame.enabled = True self.plotFrame.enabled = True self.ctrlFrame.collapsed = 0 self.plotFrame.collapsed = 0 self.__vfSelector.setCurrentNode(None) self.__xArray.SetNumberOfTuples(nFrames) self.__xArray.SetNumberOfComponents(1) self.__xArray.Allocate(nFrames) self.__xArray.SetName('frame') self.__yArray.SetNumberOfTuples(nFrames) self.__yArray.SetNumberOfComponents(1) self.__yArray.Allocate(nFrames) self.__yArray.SetName('signal intensity') self.__chartTable = vtk.vtkTable() self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.__chartTable.SetNumberOfRows(nFrames) # get the range of intensities for the mvi = self.__mvNode.GetImageData() self.__mvRange = [0, 0] for f in range(nFrames): extract = vtk.vtkImageExtractComponents() extract.SetInput(mvi) extract.SetComponents(f) extract.Update() frame = extract.GetOutput() frameRange = frame.GetScalarRange() self.__mvRange[0] = min(self.__mvRange[0], frameRange[0]) self.__mvRange[1] = max(self.__mvRange[1], frameRange[1]) self.__mvLabels = string.split( self.__mvNode.GetAttribute('MultiVolume.FrameLabels'), ',') if len(self.__mvLabels) != nFrames: return for l in range(nFrames): self.__mvLabels[l] = float(self.__mvLabels[l]) self.baselineFrames.maximum = nFrames else: self.ctrlFrame.enabled = False self.plotFrame.enabled = False self.ctrlFrame.collapsed = 1 self.plotFrame.collapsed = 1 self.__mvLabels = []
def setup(self): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) plotFrameLayout.addWidget(self.plotSettingsFrame, 0, 1) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) label = qt.QLabel('Input secondary multivolume') self.fgSelector = slicer.qMRMLNodeComboBox() self.fgSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.fgSelector.setMRMLScene(slicer.mrmlScene) self.fgSelector.addEnabled = 0 self.fgSelector.noneEnabled = 1 self.fgSelector.toolTip = "Secondary multivolume will be used for the secondary \ plot in interactive charting. As an example, this can be used to overlay the \ curve obtained by fitting a model to the data" inputFrameLayout.addRow(label, self.fgSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() label = qt.QLabel('Current frame number') # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector, 1, 1, 1, 2) ctrlFrameLayout.addWidget(self.extractButton, 2, 0, 1, 3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode', 'LabelMap', '1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.chartButton = qt.QPushButton('Chart') self.chartButton.checkable = False self.chartButton.connect('clicked()', self.onChartRequested) plotSettingsFrameLayout.addWidget(label, 0, 0) plotSettingsFrameLayout.addWidget(self.__fSelector, 0, 1) plotSettingsFrameLayout.addWidget(self.chartButton, 0, 2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotSettingsFrameLayout.addWidget(self.iCharting, 1, 0, 1, 3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) groupLabel = qt.QLabel('Interactive plotting mode:') self.iChartingMode = qt.QButtonGroup() self.iChartingIntensity = qt.QRadioButton('Signal intensity') #self.iChartingIntensity.tooltip = 'Plot range adjusted dynamically to the range over the time course for the selected pixel' self.iChartingIntensityFixedAxes = qt.QRadioButton( 'Fixed range intensity') #self.iChartingIntensityFixedAxes.tooltip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.iChartingPercent = qt.QRadioButton('Percent change') #self.iChartingPercent.tooltip = 'Percent change relative to the average of the first N frames (parameter set below)' self.iChartingIntensity.setChecked(1) self.groupWidget = qt.QWidget() self.groupLayout = qt.QFormLayout(self.groupWidget) self.groupLayout.addRow(groupLabel) self.groupLayout.addRow(self.iChartingIntensity) self.groupLayout.addRow(self.iChartingIntensityFixedAxes) self.groupLayout.addRow(self.iChartingPercent) self.baselineFrames = qt.QSpinBox() self.baselineFrames.minimum = 1 label = qt.QLabel('Number of frames for baseline calculation') self.groupLayout.addRow(label, self.baselineFrames) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for X axis') self.groupLayout.addRow(self.xLogScaleCheckBox, label) self.xLogScaleCheckBox.connect('stateChanged(int)', self.onXLogScaleRequested) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for Y axis') self.groupLayout.addRow(self.yLogScaleCheckBox, label) self.yLogScaleCheckBox.connect('stateChanged(int)', self.onYLogScaleRequested) plotSettingsFrameLayout.addWidget(self.groupWidget, 2, 0) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView, 3, 0, 1, 3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def createChart(self, sliceWidget, xy, ignoreCurrentBackground=False): if not sliceWidget and not xy: return sliceLogic = sliceWidget.sliceLogic() bgLayer = sliceLogic.GetBackgroundLayer() doIJKToRASTransformation = False bgVolumeNode = bgLayer.GetVolumeNode() if not bgVolumeNode or bgVolumeNode.GetID() != self.__bgMultiVolumeNode.GetID() or \ bgVolumeNode != self.__bgMultiVolumeNode: if not ignoreCurrentBackground: return else: doIJKToRASTransformation = True xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) if doIJKToRASTransformation: RAStoIJK = vtk.vtkMatrix4x4() self.__bgMultiVolumeNode.GetRASToIJKMatrix(RAStoIJK) ras = self.xyToRAS(sliceLogic, xy) ijkFloat = RAStoIJK.MultiplyPoint([ras[0], ras[1], ras[2], 1])[:3] bgijk = self.getIJKIntFromIJKFloat(ijkFloat) bgImage = self.__bgMultiVolumeNode.GetImageData() if not self.arePixelsWithinImageExtent(bgImage, bgijk): self.clearPlots() return nComponents = self.__bgMultiVolumeNode.GetNumberOfFrames() useFg = False fgImage = None fgijk = None if self.__fgMultiVolumeNode: fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = self.getIJKIntFromIJKFloat(fgijkFloat) fgImage = self.__fgMultiVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == bgijk[0] and fgijk[1] == bgijk[1] and fgijk[2] == bgijk[2] and \ fgImage.GetNumberOfScalarComponents() == bgImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() self.refreshArray(fgxArray, nComponents, '') fgyArray = vtk.vtkFloatArray() self.refreshArray(fgyArray, nComponents, '2nd multivolume') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = bgImage.GetScalarComponentAsDouble(bgijk[0],bgijk[1],bgijk[2],c) if math.isnan(val): val = 0 self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble(bgijk[0],bgijk[1],bgijk[2],c) if math.isnan(fgValue): fgValue = 0 fgChartTable.SetValue(c,0,self.__mvLabels[c]) fgChartTable.SetValue(c,1,fgValue) self.baselineAverageSignal = 0 if self.__chartMode == self.PERCENTAGE_CHANGE_MODE: self.computePercentageChangeWithRespectToBaseline(self.__bgMultiVolumeNode, self.__chartTable, bgijk) if useFg: self.computePercentageChangeWithRespectToBaseline(self.__fgMultiVolumeNode, fgChartTable, fgijk) self.clearPlots() self.setAxesTitle() bgPlot = self.chart.AddPlot(vtk.vtkChart.POINTS if useFg else vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(bgPlot, self.__chartTable) if useFg: fgPlot = self.chart.AddPlot(vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(fgPlot, fgChartTable)
def createNewVTKTable(self, xArray, yArray): chartTable = vtk.vtkTable() chartTable.AddColumn(xArray) chartTable.AddColumn(yArray) return chartTable
def onInputChanged(self): self.__mvNode = self.__mvSelector.currentNode() if self.__mvNode != None: Helper.SetBgFgVolumes(self.__mvNode.GetID(), None) nFrames = self.__mvNode.GetNumberOfFrames() self.__mdSlider.minimum = 0 self.__mdSlider.maximum = nFrames-1 self.__chartTable.SetNumberOfRows(nFrames) # if self.__cvn != None: # self.__cvn.SetChartNodeID(self.__cn.GetID()) self.ctrlFrame.enabled = True self.plotFrame.enabled = True self.ctrlFrame.collapsed = 0 self.plotFrame.collapsed = 0 self.__vfSelector.setCurrentNode(None) self.__xArray.SetNumberOfTuples(nFrames) self.__xArray.SetNumberOfComponents(1) self.__xArray.Allocate(nFrames) self.__xArray.SetName('frame') self.__yArray.SetNumberOfTuples(nFrames) self.__yArray.SetNumberOfComponents(1) self.__yArray.Allocate(nFrames) self.__yArray.SetName('signal intensity') self.__chartTable = vtk.vtkTable() self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.__chartTable.SetNumberOfRows(nFrames) # get the range of intensities for the mvi = self.__mvNode.GetImageData() self.__mvRange = [0,0] for f in range(nFrames): extract = vtk.vtkImageExtractComponents() extract.SetInput(mvi) extract.SetComponents(f) extract.Update() frame = extract.GetOutput() frameRange = frame.GetScalarRange() self.__mvRange[0] = min(self.__mvRange[0], frameRange[0]) self.__mvRange[1] = max(self.__mvRange[1], frameRange[1]) self.__mvLabels = string.split(self.__mvNode.GetAttribute('MultiVolume.FrameLabels'),',') if len(self.__mvLabels) != nFrames: return for l in range(nFrames): self.__mvLabels[l] = float(self.__mvLabels[l]) self.baselineFrames.maximum = nFrames else: self.ctrlFrame.enabled = False self.plotFrame.enabled = False self.ctrlFrame.collapsed = 1 self.plotFrame.collapsed = 1 self.__mvLabels = []
def setup(self, wName, parent): if self.ctrlWidget: return self.LinkViewers() self.numFrames = len(self.nodeImgList[0][0]) if parent: self.ctrlWidget = parent else: # Create seperate window self.ctrlWidget = slicer.qMRMLWidget() self.ctrlWidget.setMRMLScene(slicer.mrmlScene) self.ctrlWidget.setLayout(qt.QFormLayout()) self.ctrlWidget.setWindowTitle(wName) ctrlLayout = self.ctrlWidget.layout() # Create Slider Panel self.sliderPanel = qt.QWidget() self.sliderPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.sliderPanel) sliderLayout = self.sliderPanel.layout() if self.numFrames > 1: self.ctrlFrameLabel = qt.QLabel('Frame') self.ctrlFrameSlider = ctk.ctkSliderWidget() self.ctrlFrameSlider.connect('valueChanged(double)', self.onSliderFrameChanged) sliderLayout.addWidget(self.ctrlFrameLabel, 0, 0) sliderLayout.addWidget(self.ctrlFrameSlider, 0, 1) self.ctrlLevelLabel = qt.QLabel('Level') self.ctrlLevelSlider = ctk.ctkSliderWidget() self.ctrlLevelSlider.connect('valueChanged(double)', self.onSliderLevelChanged) sliderLayout.addWidget(self.ctrlLevelLabel, 1, 0) sliderLayout.addWidget(self.ctrlLevelSlider, 1, 1) self.ctrlWindowLabel = qt.QLabel('Window') self.ctrlWindowSlider = ctk.ctkSliderWidget() self.ctrlWindowSlider.connect('valueChanged(double)', self.onSliderWindowChanged) sliderLayout.addWidget(self.ctrlWindowLabel, 2, 0) sliderLayout.addWidget(self.ctrlWindowSlider, 2, 1) self.setSliderRangesAndValues() if self.sliceNodeList: self.orientPanel = qt.QWidget() self.orientPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.orientPanel) self.orientationButtons = {} index = 0 for orientation in self.orientations: self.orientationButtons[orientation] = qt.QRadioButton() self.orientationButtons[orientation].text = orientation # self.orientationBox.layout().addWidget(self.orientationButtons[orientation]) self.orientPanel.layout().addWidget( self.orientationButtons[orientation], 0, index) self.orientationButtons[orientation].connect( "clicked()", lambda o=orientation: self.setOrientation(o)) index += 1 self.setOrientation(self.selectedOrientation) if False: #self.plotFrame = ctk.ctkCollapsibleButton() #self.plotFrame.text = "Plotting" #self.plotFrame.collapsed = 0 self.plotFrame = qt.QWidget() plotFrameLayout = qt.QGridLayout(self.plotFrame) ctrlLayout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) #plotFrameLayout.addWidget(self.plotSettingsFrame,0,1) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) # taken from https://github.com/fedorov/MultiVolumeExplorer self.__chartView = ctk.ctkVTKChartView(self.ctrlWidget) # self.plotFrame) # self.ctrlWidget plotFrameLayout.addWidget(self.__chartView, 0, 0) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray) self.onInputChanged() self.refreshObservers() self.buttonPanel = qt.QWidget() self.buttonPanel.setLayout(qt.QGridLayout()) ctrlLayout.addWidget(self.buttonPanel) self.exitButton = qt.QPushButton("Exit") self.exitButton.toolTip = "Close down slicer." self.exitButton.name = "sviewer exit" self.buttonPanel.layout().addWidget(self.exitButton, 0, 0) self.exitButton.connect('clicked()', exit) # do not do ctrlWin.show() here - for some reason window does not pop up then return self.ctrlWidget
def createChart(self, sliceWidget, xy, ignoreCurrentBackground=False): if not sliceWidget and not xy: return sliceLogic = sliceWidget.sliceLogic() bgLayer = sliceLogic.GetBackgroundLayer() doIJKToRASTransformation = False bgVolumeNode = bgLayer.GetVolumeNode() if not bgVolumeNode or bgVolumeNode.GetID() != self.__bgMultiVolumeNode.GetID() or \ bgVolumeNode != self.__bgMultiVolumeNode: if not ignoreCurrentBackground: return else: doIJKToRASTransformation = True xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) if doIJKToRASTransformation: RAStoIJK = vtk.vtkMatrix4x4() self.__bgMultiVolumeNode.GetRASToIJKMatrix(RAStoIJK) ras = self.xyToRAS(sliceLogic, xy) ijkFloat = RAStoIJK.MultiplyPoint([ras[0], ras[1], ras[2], 1])[:3] bgijk = self.getIJKIntFromIJKFloat(ijkFloat) bgImage = self.__bgMultiVolumeNode.GetImageData() if not self.arePixelsWithinImageExtent(bgImage, bgijk): self.clearPlots() return nComponents = self.__bgMultiVolumeNode.GetNumberOfFrames() useFg = False fgImage = None fgijk = None if self.__fgMultiVolumeNode: fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = self.getIJKIntFromIJKFloat(fgijkFloat) fgImage = self.__fgMultiVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == bgijk[0] and fgijk[1] == bgijk[1] and fgijk[2] == bgijk[2] and \ fgImage.GetNumberOfScalarComponents() == bgImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() self.refreshArray(fgxArray, nComponents, '') fgyArray = vtk.vtkFloatArray() self.refreshArray(fgyArray, nComponents, '2nd multivolume') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = bgImage.GetScalarComponentAsDouble(bgijk[0], bgijk[1], bgijk[2], c) if math.isnan(val): val = 0 self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble( bgijk[0], bgijk[1], bgijk[2], c) if math.isnan(fgValue): fgValue = 0 fgChartTable.SetValue(c, 0, self.__mvLabels[c]) fgChartTable.SetValue(c, 1, fgValue) self.baselineAverageSignal = 0 if self.__chartMode == self.PERCENTAGE_CHANGE_MODE: self.computePercentageChangeWithRespectToBaseline( self.__bgMultiVolumeNode, self.__chartTable, bgijk) if useFg: self.computePercentageChangeWithRespectToBaseline( self.__fgMultiVolumeNode, fgChartTable, fgijk) self.clearPlots() self.setAxesTitle() bgPlot = self.chart.AddPlot( vtk.vtkChart.POINTS if useFg else vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(bgPlot, self.__chartTable) if useFg: fgPlot = self.chart.AddPlot(vtk.vtkChart.LINE) # bgPlot.SetLabel("Primary multivolume ") self.setPlotInputTable(fgPlot, fgChartTable)
def setup(self): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mvSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() #self.__mdSlider.setRange(0,10) #self.__mdSlider.setValue(5) label = qt.QLabel('Current frame number') ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mdSlider) # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector, 1, 1, 1, 2) ctrlFrameLayout.addWidget(self.extractButton, 2, 0, 1, 3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode', 'LabelMap', '1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.__fSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onLabelVolumeChanged) self.__fSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onLVMRMLSceneChanged) plotFrameLayout.addWidget(label, 0, 0, 1, 1) plotFrameLayout.addWidget(self.__fSelector, 0, 1, 1, 2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotFrameLayout.addWidget(self.iCharting, 1, 0, 1, 3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) label = qt.QLabel("Use intensity range to fix axis extent") label.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox = qt.QCheckBox() self.__fixedAxesCheckbox.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox.checked = False plotFrameLayout.addWidget(label, 2, 0) plotFrameLayout.addWidget(self.__fixedAxesCheckbox, 2, 1, 1, 2) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView, 3, 0, 1, 3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def processEvent(self, observee, event): if not self.iCharting.checked: return if self.__mvNode == None: return mvImage = self.__mvNode.GetImageData() nComponents = self.__mvNode.GetNumberOfFrames() # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy) ras = sliceWidget.sliceView().convertXYZToRAS(xyz) bgLayer = sliceLogic.GetBackgroundLayer() fgLayer = sliceLogic.GetForegroundLayer() volumeNode = bgLayer.GetVolumeNode() fgVolumeNode = self.fgSelector.currentNode() if not volumeNode or volumeNode.GetID() != self.__mvNode.GetID(): return if volumeNode != self.__mvNode: return nameLabel = volumeNode.GetName() xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage.GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): # pixel outside the valid extent return useFg = False if fgVolumeNode: fgxyToIJK = fgLayer.GetXYToIJKTransform() fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = [] for element in fgijkFloat: try: index = int(round(element)) except ValueError: index = 0 fgijk.append(index) fgImage = fgVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == ijk[0] and fgijk[1] == ijk[1] and fgijk[2] == ijk[2] and \ fgImage.GetNumberOfScalarComponents() == mvImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = mvImage.GetScalarComponentAsDouble(ijk[0], ijk[1], ijk[2], c) self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) fgChartTable.SetValue(c, 0, self.__mvLabels[c]) fgChartTable.SetValue(c, 1, fgValue) baselineAverageSignal = 0 if self.iChartingPercent.checked: # check if percent plotting was requested and recalculate nBaselines = min(self.baselineFrames.value, nComponents) for c in range(nBaselines): baselineAverageSignal += mvImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) baselineAverageSignal /= nBaselines if baselineAverageSignal != 0: for c in range(nComponents): intensity = mvImage.GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], c) self.__chartTable.SetValue( c, 1, (intensity / baselineAverageSignal - 1) * 100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) if self.iChartingPercent.checked and baselineAverageSignal != 0: self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') else: self.__chart.GetAxis(0).SetTitle('signal intensity') tag = str( self.__mvNode.GetAttribute( 'MultiVolume.FrameIdentifyingDICOMTagName')) units = str( self.__mvNode.GetAttribute( 'MultiVolume.FrameIdentifyingDICOMTagUnits')) xTitle = tag + ', ' + units self.__chart.GetAxis(1).SetTitle(xTitle) if self.iChartingIntensityFixedAxes.checked == True: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) self.__chart.GetAxis(0).SetRange(self.__mvRange[0], self.__mvRange[1]) else: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) plot.SetInput(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) fgplot.SetInput(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) plot.SetInput(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of ' + title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of ' + title)
def __init__(self,param): super(LesionFormWidget,self).__init__() # parameters node keeps all that is needed to render # the form and to store the scores self.param = param self.widget = qt.QWidget() self.layout = qt.QHBoxLayout(self.widget) lesionNameWidget = qt.QWidget() scoreSheetWidget = qt.QWidget() plotWidget = qt.QWidget() lnLayout = qt.QVBoxLayout(lesionNameWidget) ssLayout = qt.QVBoxLayout(scoreSheetWidget) pLayout = qt.QVBoxLayout(plotWidget) lesionName = qt.QLabel(self.param.lesionName) lnLayout.addWidget(lesionName) w = qt.QWidget() wl = qt.QHBoxLayout(w) for i in range(0,6): if i: label = qt.QLabel(str(i)) else: label = qt.QLabel('') wl.addWidget(label) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) t2label = qt.QLabel('T2W') wl.addWidget(t2label) t2radios = [] self.t2group = qt.QButtonGroup() for i in range(1,6): t2radios.append(qt.QRadioButton()) self.t2group.addButton(t2radios[-1],i) wl.addWidget(t2radios[-1]) self.t2group.connect('buttonClicked(int)', self.onT2scoreUpdated) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) dwilabel = qt.QLabel('DWI') wl.addWidget(dwilabel) dwiradios = [] self.dwigroup = qt.QButtonGroup() for i in range(1,6): dwiradios.append(qt.QRadioButton()) self.dwigroup.addButton(dwiradios[-1],i) wl.addWidget(dwiradios[-1]) self.dwigroup.connect('buttonClicked(int)', self.onDWIscoreUpdated) ssLayout.addWidget(w) w = qt.QWidget() wl = qt.QHBoxLayout(w) dcelabel = qt.QLabel('DCE') wl.addWidget(dcelabel) dceradios = [] self.dcegroup = qt.QButtonGroup() for i in range(1,6): dceradios.append(qt.QRadioButton()) self.dcegroup.addButton(dceradios[-1],i) wl.addWidget(dceradios[-1]) self.dcegroup.connect('buttonClicked(int)', self.onDCEscoreUpdated) ssLayout.addWidget(w) chartView = ctk.ctkVTKChartView(plotWidget) chart = chartView.chart() table = vtk.vtkTable() x = vtk.vtkFloatArray() y = vtk.vtkFloatArray() x.SetName('time point') y.SetName('signal intensity') table.AddColumn(x) table.AddColumn(y) table.SetNumberOfRows(100) for c in range(len(self.param.x)): table.SetValue(c,0,self.param.x[c]) table.SetValue(c,1,self.param.y[c]) plot = chart.AddPlot(0) plot.SetInput(table,0,1) chart.AddPlot(0) cw = qt.QWidget() cwl = qt.QVBoxLayout(cw) cwl.addWidget(chartView) pLayout.addWidget(cw) self.layout.addWidget(lesionNameWidget) self.layout.addWidget(scoreSheetWidget) self.layout.addWidget(plotWidget)
def setup( self ): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) self.plotSettingsFrame = ctk.ctkCollapsibleButton() self.plotSettingsFrame.text = "Settings" self.plotSettingsFrame.collapsed = 1 plotSettingsFrameLayout = qt.QGridLayout(self.plotSettingsFrame) plotFrameLayout.addWidget(self.plotSettingsFrame,0,1) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) label = qt.QLabel('Input secondary multivolume') self.fgSelector = slicer.qMRMLNodeComboBox() self.fgSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.fgSelector.setMRMLScene(slicer.mrmlScene) self.fgSelector.addEnabled = 0 self.fgSelector.noneEnabled = 1 self.fgSelector.toolTip = "Secondary multivolume will be used for the secondary \ plot in interactive charting. As an example, this can be used to overlay the \ curve obtained by fitting a model to the data" inputFrameLayout.addRow(label, self.fgSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() label = qt.QLabel('Current frame number') # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector,1,1,1,2) ctrlFrameLayout.addWidget(self.extractButton,2,0,1,3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap','1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.chartButton = qt.QPushButton('Chart') self.chartButton.checkable = False self.chartButton.connect('clicked()', self.onChartRequested) plotSettingsFrameLayout.addWidget(label,0,0) plotSettingsFrameLayout.addWidget(self.__fSelector,0,1) plotSettingsFrameLayout.addWidget(self.chartButton,0,2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotSettingsFrameLayout.addWidget(self.iCharting,1,0,1,3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) groupLabel = qt.QLabel('Interactive plotting mode:') self.iChartingMode = qt.QButtonGroup() self.iChartingIntensity = qt.QRadioButton('Signal intensity') #self.iChartingIntensity.tooltip = 'Plot range adjusted dynamically to the range over the time course for the selected pixel' self.iChartingIntensityFixedAxes = qt.QRadioButton('Fixed range intensity') #self.iChartingIntensityFixedAxes.tooltip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.iChartingPercent = qt.QRadioButton('Percent change') #self.iChartingPercent.tooltip = 'Percent change relative to the average of the first N frames (parameter set below)' self.iChartingIntensity.setChecked(1) self.groupWidget = qt.QWidget() self.groupLayout = qt.QFormLayout(self.groupWidget) self.groupLayout.addRow(groupLabel) self.groupLayout.addRow(self.iChartingIntensity) self.groupLayout.addRow(self.iChartingIntensityFixedAxes) self.groupLayout.addRow(self.iChartingPercent) self.baselineFrames = qt.QSpinBox() self.baselineFrames.minimum = 1 label = qt.QLabel('Number of frames for baseline calculation') self.groupLayout.addRow(label,self.baselineFrames) self.xLogScaleCheckBox = qt.QCheckBox() self.xLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for X axis') self.groupLayout.addRow(self.xLogScaleCheckBox,label) self.xLogScaleCheckBox.connect('stateChanged(int)', self.onXLogScaleRequested) self.yLogScaleCheckBox = qt.QCheckBox() self.yLogScaleCheckBox.setChecked(0) label = qt.QLabel('Use log scale for Y axis') self.groupLayout.addRow(self.yLogScaleCheckBox,label) self.yLogScaleCheckBox.connect('stateChanged(int)', self.onYLogScaleRequested) plotSettingsFrameLayout.addWidget(self.groupWidget,2,0) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView,3,0,1,3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def setup( self ): self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) w = qt.QWidget() layout = qt.QGridLayout() w.setLayout(layout) self.layout.addWidget(w) w.show() self.layout = layout # create frames self.inputFrame = ctk.ctkCollapsibleButton() self.inputFrame.text = "Input" self.inputFrame.collapsed = 0 inputFrameLayout = qt.QFormLayout(self.inputFrame) self.layout.addWidget(self.inputFrame) self.ctrlFrame = ctk.ctkCollapsibleButton() self.ctrlFrame.text = "Frame control" self.ctrlFrame.collapsed = 0 ctrlFrameLayout = qt.QGridLayout(self.ctrlFrame) self.layout.addWidget(self.ctrlFrame) self.plotFrame = ctk.ctkCollapsibleButton() self.plotFrame.text = "Plotting" self.plotFrame.collapsed = 0 plotFrameLayout = qt.QGridLayout(self.plotFrame) self.layout.addWidget(self.plotFrame) label = qt.QLabel('Input multivolume') self.__mvSelector = slicer.qMRMLNodeComboBox() self.__mvSelector.nodeTypes = ['vtkMRMLMultiVolumeNode'] self.__mvSelector.setMRMLScene(slicer.mrmlScene) self.__mvSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVCMRMLSceneChanged) self.__mvSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onInputChanged) self.__mvSelector.addEnabled = 0 inputFrameLayout.addRow(label, self.__mvSelector) ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mvSelector) # TODO: initialize the slider based on the contents of the labels array # slider to scroll over metadata stored in the vector container being explored self.__mdSlider = ctk.ctkSliderWidget() #self.__mdSlider.setRange(0,10) #self.__mdSlider.setValue(5) label = qt.QLabel('Current frame number') ##self.layout.addWidget(label) ##self.layout.addWidget(self.__mdSlider) # "play" control self.playButton = qt.QPushButton('Play') self.playButton.toolTip = 'Iterate over multivolume frames' self.playButton.checkable = True ctrlFrameLayout.addWidget(label, 0, 0) ctrlFrameLayout.addWidget(self.__mdSlider, 0, 1) ctrlFrameLayout.addWidget(self.playButton, 0, 2) self.playButton.connect('toggled(bool)', self.onPlayButtonToggled) self.__mdSlider.connect('valueChanged(double)', self.onSliderChanged) label = qt.QLabel('Current frame copy') self.__vfSelector = slicer.qMRMLNodeComboBox() self.__vfSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__vfSelector.setMRMLScene(slicer.mrmlScene) self.__vfSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onVFMRMLSceneChanged) self.__vfSelector.addEnabled = 1 self.__vfSelector.enabled = 0 # do not show "children" of vtkMRMLScalarVolumeNode self.__vfSelector.hideChildNodeTypes = ["vtkMRMLDiffusionWeightedVolumeNode", \ "vtkMRMLDiffusionTensorVolumeNode", "vtkMRMLVectorVolumeNode"] self.extractFrame = False self.extractButton = qt.QPushButton('Enable current frame copying') self.extractButton.checkable = True self.extractButton.connect('toggled(bool)', self.onExtractFrameToggled) ctrlFrameLayout.addWidget(label, 1, 0) ctrlFrameLayout.addWidget(self.__vfSelector,1,1,1,2) ctrlFrameLayout.addWidget(self.extractButton,2,0,1,3) # initialize slice observers (from DataProbe.py) # keep list of pairs: [observee,tag] so they can be removed easily self.styleObserverTags = [] # keep a map of interactor styles to sliceWidgets so we can easily get sliceLogic self.sliceWidgetsPerStyle = {} self.refreshObservers() # label map for probing label = qt.QLabel('Probed label volume') self.__fSelector = slicer.qMRMLNodeComboBox() self.__fSelector.nodeTypes = ['vtkMRMLScalarVolumeNode'] self.__fSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap','1') self.__fSelector.toolTip = 'Label map to be probed' self.__fSelector.setMRMLScene(slicer.mrmlScene) self.__fSelector.addEnabled = 0 self.__fSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onLabelVolumeChanged) self.__fSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onLVMRMLSceneChanged) plotFrameLayout.addWidget(label,0,0,1,1) plotFrameLayout.addWidget(self.__fSelector,0,1,1,2) self.iCharting = qt.QPushButton() self.iCharting.text = 'Enable interactive charting' self.iCharting.checkable = True plotFrameLayout.addWidget(self.iCharting,1,0,1,3) self.iCharting.setChecked(True) self.iCharting.connect('toggled(bool)', self.onInteractiveChartingChanged) label = qt.QLabel("Use intensity range to fix axis extent") label.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox = qt.QCheckBox() self.__fixedAxesCheckbox.toolTip = "If checked, the extent of the vertical axis of the plot will be fixed to the range of the intensities in the input MultiVolume" self.__fixedAxesCheckbox.checked = False plotFrameLayout.addWidget(label, 2, 0) plotFrameLayout.addWidget(self.__fixedAxesCheckbox, 2,1,1,2) # add chart container widget self.__chartView = ctk.ctkVTKChartView(w) plotFrameLayout.addWidget(self.__chartView,3,0,1,3) self.__chart = self.__chartView.chart() self.__chartTable = vtk.vtkTable() self.__xArray = vtk.vtkFloatArray() self.__yArray = vtk.vtkFloatArray() # will crash if there is no name self.__xArray.SetName('') self.__yArray.SetName('signal intensity') self.__chartTable.AddColumn(self.__xArray) self.__chartTable.AddColumn(self.__yArray)
def processEvent(self,observee,event): if not self.iCharting.checked: return if self.__mvNode == None: return mvImage = self.__mvNode.GetImageData() nComponents = self.__mvNode.GetNumberOfFrames() # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() xyz = sliceWidget.sliceView().convertDeviceToXYZ(xy); ras = sliceWidget.sliceView().convertXYZToRAS(xyz) bgLayer = sliceLogic.GetBackgroundLayer() fgLayer = sliceLogic.GetForegroundLayer() volumeNode = bgLayer.GetVolumeNode() fgVolumeNode = self.fgSelector.currentNode() if not volumeNode or volumeNode.GetID() != self.__mvNode.GetID(): return if volumeNode != self.__mvNode: return nameLabel = volumeNode.GetName() xyToIJK = bgLayer.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage.GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): # pixel outside the valid extent return useFg = False if fgVolumeNode: fgxyToIJK = fgLayer.GetXYToIJKTransform() fgijkFloat = xyToIJK.TransformDoublePoint(xyz) fgijk = [] for element in fgijkFloat: try: index = int(round(element)) except ValueError: index = 0 fgijk.append(index) fgImage = fgVolumeNode.GetImageData() fgChartTable = vtk.vtkTable() if fgijk[0] == ijk[0] and fgijk[1] == ijk[1] and fgijk[2] == ijk[2] and \ fgImage.GetNumberOfScalarComponents() == mvImage.GetNumberOfScalarComponents(): useFg = True fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK for c in range(nComponents): val = mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if useFg: fgValue = fgImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) fgChartTable.SetValue(c,0,self.__mvLabels[c]) fgChartTable.SetValue(c,1,fgValue) baselineAverageSignal = 0 if self.iChartingPercent.checked: # check if percent plotting was requested and recalculate nBaselines = min(self.baselineFrames.value,nComponents) for c in range(nBaselines): baselineAverageSignal += mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) baselineAverageSignal /= nBaselines if baselineAverageSignal != 0: for c in range(nComponents): intensity = mvImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) self.__chartTable.SetValue(c,1,(intensity/baselineAverageSignal-1)*100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) if self.iChartingPercent.checked and baselineAverageSignal != 0: self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') else: self.__chart.GetAxis(0).SetTitle('signal intensity') tag = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagName')) units = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits')) xTitle = tag+', '+units self.__chart.GetAxis(1).SetTitle(xTitle) if self.iChartingIntensityFixedAxes.checked == True: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) self.__chart.GetAxis(0).SetRange(self.__mvRange[0],self.__mvRange[1]) else: self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) plot.SetInput(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) fgplot.SetInput(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) plot.SetInput(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of '+title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of '+title)
def processEvent(self, observee, event): #if not self.iCharting.checked: # return fgImages = self.nodeImgList[0] mvImage = fgImages[0] fgNodes = self.nodeList[0] nComponents = self.numFrames # TODO: use a timer to delay calculation and compress events if event == 'LeaveEvent': # reset all the readouts # TODO: reset the label text return if not self.sliceWidgetsPerStyle.has_key(observee): return sliceWidget = self.sliceWidgetsPerStyle[observee] sliceLogic = sliceWidget.sliceLogic() interactor = observee.GetInteractor() xy = interactor.GetEventPosition() coordinates = [] # we need a 4 element point to be able to multiply further down coordinates.append(xy[0]) coordinates.append(xy[1]) coordinates.append(0) coordinates.append(1) xyToRas = sliceLogic.GetSliceNode().GetXYToRAS() rasPos = xyToRas.MultiplyPoint(coordinates) # VTK_CREATE(vtkMatrix4x4, rasToijk); rasToijk = vtk.vtkMatrix4x4() fgNodes[0].GetRASToIJKMatrix(rasToijk) ijkFloat = rasToijk.MultiplyPoint(rasPos) ijk = [] for element in ijkFloat: try: index = int(round(element)) except ValueError: index = 0 ijk.append(index) extent = mvImage[0].GetExtent() if not (ijk[0]>=extent[0] and ijk[0]<=extent[1] and \ ijk[1]>=extent[2] and ijk[1]<=extent[3] and \ ijk[2]>=extent[4] and ijk[2]<=extent[5]): return nComponents = self.numFrames # for testing # nComponents=1 if True: fgxArray = vtk.vtkFloatArray() fgxArray.SetNumberOfTuples(nComponents) fgxArray.SetNumberOfComponents(1) fgxArray.Allocate(nComponents) fgxArray.SetName('frame') fgyArray = vtk.vtkFloatArray() fgyArray.SetNumberOfTuples(nComponents) fgyArray.SetNumberOfComponents(1) fgyArray.Allocate(nComponents) fgyArray.SetName('signal intensity') # will crash if there is no name fgChartTable = vtk.vtkTable() fgChartTable.AddColumn(fgxArray) fgChartTable.AddColumn(fgyArray) fgChartTable.SetNumberOfRows(nComponents) # get the vector of values at IJK if (self.ctrlLevelSlider.maximum - self.ctrlLevelSlider.minimum) > 20: intFlag = True else: intFlag = False disVal = [] if self.ctrlFrameSlider: cInd = int(self.ctrlFrameSlider.value) else: cInd = 0 for c in range(nComponents): for img in fgImages: # for c in range(1): iLen = len(img) if c < iLen: val = img[c].GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], 0) else: val = img[iLen - 1].GetScalarComponentAsDouble( ijk[0], ijk[1], ijk[2], 0) if intFlag: val = int(val) else: val = round(val * 100) / 100.0 # Kilian: will only show last image - change later self.__chartTable.SetValue(c, 0, self.__mvLabels[c]) self.__chartTable.SetValue(c, 1, val) if cInd == c: disVal.append(val) #if useFg: # fgValue = fgImage.GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],0) # fgChartTable.SetValue(c,0,self.__mvLabels[c]) # fgChartTable.SetValue(c,1,fgValue) self.valueFrameValues.setText(disVal) # To disable plot uncomment # return baselineAverageSignal = 0 # if self.iChartingPercent.checked: # # check if percent plotting was requested and recalculate # nBaselines = min(self.baselineFrames.value,nComponents) # for c in range(nBaselines): # baselineAverageSignal += mvImage[0].GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) # baselineAverageSignal /= nBaselines # if baselineAverageSignal != 0: # for c in range(nComponents): # intensity = mvImage[0].GetScalarComponentAsDouble(ijk[0],ijk[1],ijk[2],c) # self.__chartTable.SetValue(c,1,(intensity/baselineAverageSignal-1)*100.) self.__chart.RemovePlot(0) self.__chart.RemovePlot(0) #if self.iChartingPercent.checked and baselineAverageSignal != 0: # self.__chart.GetAxis(0).SetTitle('change relative to baseline, %') #else: self.__chart.GetAxis(0).SetTitle('signal intensity') #tag = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagName')) #units = str(self.__mvNode.GetAttribute('MultiVolume.FrameIdentifyingDICOMTagUnits')) #xTitle = tag+', '+units self.__chart.GetAxis(1).SetTitle("Time") #if self.iChartingIntensityFixedAxes.checked == True: # self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.FIXED) # self.__chart.GetAxis(0).SetRange(self.__mvRange[0],self.__mvRange[1]) # self.__chart.GetAxis(0).SetRange(2000,6000) # self.__chart.GetAxis(1).SetBehavior(vtk.vtkAxis.FIXED) # self.__chart.GetAxis(1).SetRange(2000,6000) #else: # self.__chart.GetAxis(0).SetBehavior(vtk.vtkAxis.AUTO) # if useFg: useFg = False if useFg: plot = self.__chart.AddPlot(vtk.vtkChart.POINTS) if vtk.VTK_MAJOR_VERSION <= 5: plot.SetInput(self.__chartTable, 0, 1) else: plot.SetInputData(self.__chartTable, 0, 1) fgplot = self.__chart.AddPlot(vtk.vtkChart.LINE) if vtk.VTK_MAJOR_VERSION <= 5: fgplot.SetInput(fgChartTable, 0, 1) else: fgplot.SetInputData(fgChartTable, 0, 1) else: plot = self.__chart.AddPlot(vtk.vtkChart.LINE) if vtk.VTK_MAJOR_VERSION <= 5: plot.SetInput(self.__chartTable, 0, 1) else: plot.SetInputData(self.__chartTable, 0, 1) if self.xLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(1).GetTitle() self.__chart.GetAxis(1).SetTitle('log of ' + title) if self.yLogScaleCheckBox.checkState() == 2: title = self.__chart.GetAxis(0).GetTitle() self.__chart.GetAxis(0).SetTitle('log of ' + title)