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

From Slicer Wiki
Jump to: navigation, search
(28 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
<noinclude>{{documentation/versioncheck}}</noinclude>
 
<noinclude>{{documentation/versioncheck}}</noinclude>
{{Clear|right}}{{TOC right}}
+
{{Clear}}{{TOC right}}
  
= Slicer Plotting Overview and Acknowledgements =
+
= Slicer plotting overview and acknowledgements =
  
Slicer provides Plotting facilities that include a Plot View that can be packed in the layout, similar to the Slice Views and 3D Views. The architecture also includes nodes that represent the data to be displayed in the plot as well as nodes to represent the display properties of the data and the plot itself. Plot can be serialized with the MRML scene, including the plot data and display properties. In Addition, the PlotView is connected with the Table Module and Views allowing the plotting of arrays with a simple click.
+
Slicer provides Plotting facilities that include a plot view that can be displayed in the view layout, similarly to slice 3D views. Plot data is stored in table nodes, and plot series, chart, and view nodes define which table column need to be displayed and how. Plot can be serialized with the MRML scene, including the plot data and display properties. Plot series and charts can be created and edited in Plots module and plots can be also generated directly from Tables module by a single click.
  
Author:<br>
+
Authors:<br>
 
<b>Davide Punzo</b> (Kapteyn Astronomical Institute, University of Groningen) <br>
 
<b>Davide Punzo</b> (Kapteyn Astronomical Institute, University of Groningen) <br>
 +
<b>Andras Lasso</b> (PerkLab, Queen's University) <br>
  
 
Contributors: <br>
 
Contributors: <br>
<b>Andras Lasso</b> (PerkLab, Queen's) <br>
 
 
<b>Jean-Christophe Fillion-Robin</b> (Kitware) <br>  
 
<b>Jean-Christophe Fillion-Robin</b> (Kitware) <br>  
 
<b>Steve Pieper</b> (Isomics) <br> <br>
 
<b>Steve Pieper</b> (Isomics) <br> <br>
Line 25: Line 25:
  
 
= Plot capabilities =
 
= Plot capabilities =
* Plot are represented in the MRML scene
+
* Multiple plots types (Line, Bar, Scatter, Scatter bar), shown in standard view layouts.
* Multiple Plot Views can be in a layout
+
* Configurable chart and axis title, legend, grid lines.
* Each Plot View can display any Plot in the MRML scene
+
* Use indexes (0, 1, 2, ...) or a table column for X axis values.
* Each Plot can display multiple Arrays of data from a Table or more Tables
+
* Multiple plot series can be added to a single plot chart (even showing data from different tables, with different types - plot, bar), and the same series can be added to multiple charts. The same plot chart can be shown in any plot views (even simultaneously).
* Plot Views can [[#Signals|emit signals]] back to the application as the user interacts with a Plot
+
* Label can be assigned to each data point (shown in tooltip when hovering over a data point).
* Multiple plots types (Line, Bar, Scatter)
+
* Interactive editing of data points by drag-and-drop (data in referenced table nodes is updated).
* Zooming using the mouse
+
* Interactive selection of data points (rectangular or free-hand selection).
* Interactively select data (regions or click and drag).
+
* Plot data and display properties are stored in the MRML scene.
* Axis labels
+
* Plot view can be embedded into module user interfaces. Plot views can [[#Signals|emit signals]] back to the application as the user interacts with a plot, which allows modules to perform additional processing on the selected data points.
* Legends
 
  
<br>
+
What is the difference between Slicer Plot and Chart?
<b>relevant FAQ</b>: What is the difference between Slicer Plot and Chart ? [https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ#What_is_the_difference_between_Slicer_Plot_and_Chart_.3F]<br>
+
[[Documentation/{{documentation/version}}/Developers/FAQ#What_is_the_difference_between_Slicer_Plot_and_Chart_.3F | See FAQ.]]
  
 
= Shortcuts and Interactions =
 
= Shortcuts and Interactions =
 
The Plot infrastructure allow the following interaction:
 
The Plot infrastructure allow the following interaction:
  
"Left Click" - selections: rectangular, lasso and Click and Drag (Key_S to change the selection mode)
+
* Left mouse button: depends on interaction mode of the view
"Middle Click" - pan
+
** Pan view: pan view
"Middle Scroll" - zoom
+
** Select points: select points using rectangular selection
"Right Click" - zoom in a rectangular selection
+
** Freehand select points: select points using free-form selection
 +
** Move points: move data points by drag-and-drop; this changes values in the referenced table node
 +
* Middle mouse button: pan view (except in pan view mode; in that case it zooms to selected rectangular region)
 +
* Right mouse button: zoom in/out along X and Y axes
 +
* S: switch interaction mode (pan/select points/.../move points)
 +
* R: reset view to show all data series
 +
* U: unselect the points selection
  
"Key_S" - change selection mode
+
=Architecture=
"Key_R" - restore axis and frame zoom
+
 
 +
== MRML Nodes ==
 +
 
 +
; [{{doxygen-class-url|vtkMRMLTableNode}} vtkMRMLTableNode]
 +
: Table node stores values that specify data point positions or bar heights in the plots.
 +
 
 +
; [{{doxygen-class-url|vtkMRMLPlotSeriesNode}} vtkMRMLPlotSeriesNode]
 +
: Defines a data series by referring to a table node and column name(s) for X and Y axes and labels.
 +
: It also defines display properties, such as plot type, color, line style.
 +
: Line and bar plots only require Y axis (points along X axis are equally spaced), scatter plots require two input data columns, for X and Y axes.
 +
 
 +
; [{{doxygen-class-url|vtkMRMLPlotChartNode}} vtkMRMLPlotChartNode]
 +
: Specifies which data series need to be shown in the chart.
 +
: Also contains global display properties for the chart, such as titles and font style.
 +
 
 +
; [{{doxygen-class-url|vtkMRMLPlotViewNode}} vtkMRMLPlotViewNode]
 +
: Specifies which chart is to be displayed in the plot view and how the user can interact with it.
 +
: There has to be exactly one plot view node for each plot view widget. This class can not be created or copied unless is connected with a plot view.
  
"Key_Shift + Left click" - pan
+
== Widgets ==
"Key_Shift + Middle click" - selections: rectangular, lasso and Click and Drag (Key_S to change the selection mode)
 
  
=Architecture=
+
; [{{doxygen-class-url|qMRMLPlotView}} qMRMLPlotView]
== Plot View ==
+
: Displays a plot. It can be embedded into a module user interface.
  
 
; [{{doxygen-class-url|qMRMLPlotWidget}} qMRMLPlotWidget]
 
; [{{doxygen-class-url|qMRMLPlotWidget}} qMRMLPlotWidget]
: The toplevel plotting widget that is packed in layout. Subclass of qMRMLWidget. Contains a qMRMLPlotView and a qMRMLPlotViewControllerWidget.
+
: Displays a plot and in a popup window a plot view controller widget [{{doxygen-class-url|qMRMLPlotViewControllerWidget}} plot view controller widget].
; [{{doxygen-class-url|qMRMLPlotViewWidget}} qMRMLPlotViewWidget]
+
 
: Display canvas of the plot. This is currently a subclass of ctkVTKChartView. This allow 2D plotting (for 3D plotting it will require to update and factorize the ctkVTKChartView).
+
; [{{doxygen-class-url|qMRMLPlotSeriesPropertiesWidget}} qMRMLPlotSeriesPropertiesWidget]
; [{{doxygen-class-url|qMRMLPlotViewControllerWidget}} qMRMLPlotViewControllerWidget]
+
: Display/edit properties of a plot series node.
: Widget to control the content and display of a plot.
 
  
== MRML Nodes ==
+
; [{{doxygen-class-url|qMRMLPlotChartPropertiesWidget}} qMRMLPlotChartPropertiesWidget]
 +
: Display/edit properties of a plot series node.
  
; [{{doxygen-class-url|vtkMRMLPlotViewNode}} vtkMRMLPlotViewNode]
+
; [{{doxygen-class-url|qMRMLPlotViewControllerWidget}} qMRMLPlotViewControllerWidget]
: Node associated with a PlotViewWidget. This is a 1-to-1 Node class connected with a PlotViewWidget. This class can not be created or copied unless is connected with a PlotWidget.
+
: Display/edit properties of a plot view node.
; [{{doxygen-class-url|vtkMRMLPlotChartNode}} vtkMRMLPlotChartNode]
 
: Node keeps track of which plot (PlotDataNode) to display in a PlotView. There can be multiple PlotChart in a scene and a given PlotView can display any of the PlotChart.
 
; [{{doxygen-class-url|vtkMRMLPlotDataNode}} vtkMRMLPlotDataNode]
 
: Represents the vtkPlot (the data) that can be displayed in a PlotView.
 
  
 
= Constructing a plot =  
 
= Constructing a plot =  
Below is an example in python to construct and display a plot communicating completely at the level of MRML.
+
Below is an example in python to construct and display a plot communicating completely at the level of MRML. Note: this functionality is not available in Slicer 4.8, please use a recent SlicerPreview nightly build.
 +
 
 
<pre lang="python">
 
<pre lang="python">
 
import slicer
 
import slicer
 
import math
 
import math
  
# Switch to a layout (OneUpPlotView) that contains a Plot View to initiate the construction of the widget and Plot View Node
+
# Create table with x, cos, sin columns
lns = slicer.mrmlScene.GetNodesByClass('vtkMRMLLayoutNode')
 
lns.InitTraversal()
 
ln = lns.GetNextItemAsObject()
 
ln.SetViewArrangement(ln.SlicerLayoutOneUpPlotView)
 
  
# Create a vtkTable
+
tableNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
table = vtk.vtkTable()
+
table = tableNode.GetTable()
  
# Fill the table
 
 
arrX = vtk.vtkFloatArray()
 
arrX = vtk.vtkFloatArray()
arrX.SetName("X Axis")
+
arrX.SetName("x")
 
table.AddColumn(arrX)
 
table.AddColumn(arrX)
  
arrC = vtk.vtkFloatArray()
+
arrY1 = vtk.vtkFloatArray()
arrC.SetName("Cosine")
+
arrY1.SetName("cos")
table.AddColumn(arrC)
+
table.AddColumn(arrY1)
  
arrS = vtk.vtkFloatArray()
+
arrY2 = vtk.vtkFloatArray()
arrS.SetName("Sine")
+
arrY2.SetName("sin")
table.AddColumn(arrS)
+
table.AddColumn(arrY2)
  
 
# Fill in the table with some example values
 
# Fill in the table with some example values
 +
 +
import math
 
numPoints = 69
 
numPoints = 69
 
inc = 7.5 / (numPoints - 1)
 
inc = 7.5 / (numPoints - 1)
 
table.SetNumberOfRows(numPoints)
 
table.SetNumberOfRows(numPoints)
 
for i in range(numPoints):
 
for i in range(numPoints):
  table.SetValue(i, 0, i * inc )
+
  table.SetValue(i, 0, i * inc )
  table.SetValue(i, 1, math.cos(i * inc))
+
  table.SetValue(i, 1, math.cos(i * inc))
  table.SetValue(i, 2, math.sin(i * inc))
+
  table.SetValue(i, 2, math.sin(i * inc))
 +
 
 +
# Create two plot series nodes
 +
 
 +
plotSeriesNode1 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotSeriesNode", "My first")
 +
plotSeriesNode1.SetAndObserveTableNodeID(tableNode.GetID())
 +
plotSeriesNode1.SetXColumnName("x")
 +
plotSeriesNode1.SetYColumnName("cos")
 +
plotSeriesNode1.SetPlotType(slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter)
 +
plotSeriesNode1.SetLineStyle(slicer.vtkMRMLPlotSeriesNode.LineStyleNone)
 +
plotSeriesNode1.SetMarkerStyle(slicer.vtkMRMLPlotSeriesNode.MarkerStyleSquare)
 +
plotSeriesNode1.SetUniqueColor()
  
# Create a MRMLTableNode
+
plotSeriesNode2 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotSeriesNode", "My second")
TableNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLTableNode())
+
plotSeriesNode2.SetAndObserveTableNodeID(tableNode.GetID())
TableNode.SetAndObserveTable(table)
+
plotSeriesNode2.SetXColumnName("x")
 +
plotSeriesNode2.SetYColumnName("sin")
 +
plotSeriesNode2.SetPlotType(slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter)
 +
plotSeriesNode2.SetUniqueColor()
  
# Create two PlotDataNodes
+
# Create plot chart node
plotDataNode1 = slicer.mrmlScene.AddNode(slicer.vtkMRMLPlotDataNode())
 
plotDataNode2 = slicer.mrmlScene.AddNode(slicer.vtkMRMLPlotDataNode())
 
  
# Set and Observe the MRMLTableNodeID
+
plotChartNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotChartNode")
plotDataNode1.SetName(arrC.GetName())
+
plotChartNode.AddAndObservePlotSeriesNodeID(plotSeriesNode1.GetID())
plotDataNode1.SetAndObserveTableNodeID(TableNode.GetID());
+
plotChartNode.AddAndObservePlotSeriesNodeID(plotSeriesNode2.GetID())
plotDataNode1.SetXColumnName(TableNode.GetColumnName(0));
+
plotChartNode.SetTitle('A simple plot with 2 curves')
plotDataNode1.SetYColumnName(TableNode.GetColumnName(1));
+
plotChartNode.SetXAxisTitle('Something in x')
 +
plotChartNode.SetYAxisTitle('Something in y')
  
plotDataNode2.SetName(arrS.GetName())
+
# Switch to a layout that contains a plot view to create a plot widget
plotDataNode2.SetAndObserveTableNodeID(TableNode.GetID());
 
plotDataNode1.SetXColumnName(TableNode.GetColumnName(0));
 
plotDataNode1.SetYColumnName(TableNode.GetColumnName(2));
 
  
# Create a PlotChart node
+
layoutManager = slicer.app.layoutManager()
plotChartNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLPlotChartNode())
+
layoutWithPlot = slicer.modules.plots.logic().GetLayoutWithPlot(layoutManager.layout)
# Add and Observe plots IDs in PlotLayout
+
layoutManager.setLayout(layoutWithPlot)
plotChartNode.AddAndObservePlotDataNodeID(plotDataNode1.GetID());
 
plotChartNode.AddAndObservePlotDataNodeID(plotDataNode2.GetID());
 
  
# Create PlotView node
+
# Select chart in plot view
pvns = slicer.mrmlScene.GetNodesByClass('vtkMRMLPlotViewNode')
 
pvns.InitTraversal()
 
plotViewNode = pvns.GetNextItemAsObject()
 
# Set plotLayout ID in PlotView
 
plotViewNode.SetPlotChartNodeID(plotChartNode.GetID());
 
  
# Set a few properties on the Plot.
+
plotWidget = layoutManager.plotWidget(0)
plotChartNode.SetAttribute('TitleName', 'A simple plot with 2 curves')
+
plotViewNode = plotWidget.mrmlPlotViewNode()
plotChartNode.SetAttribute('XAxisLabelName', 'Something in x')
+
plotViewNode.SetPlotChartNodeID(plotChartNode.GetID())
plotChartNode.SetAttribute('YAxisLabelName', 'Something in y')
 
plotChartNode.SetPlotType('Scatter')
 
 
</pre>
 
</pre>
  
This code produces the chart below.
+
This code produces the plot below.
  
 
[[Image:VtkPlot.png|A simple plot.|1200px]]
 
[[Image:VtkPlot.png|A simple plot.|1200px]]
 
= Properties =
 
 
Individual properties (such as the color) of a plot
 
can be changed calling the vtkPlot stored in a vtkMRMLPlotNode
 
 
In addition a set of properties regarding the "frame" are available for a PlotLayout.
 
These are stored as Attributes of PlotChartNode.
 
Available properties are:
 
 
 
"Type" - "Line", "Line and Scatter", "Scatter", "Bar"
 
"TitleName" - title ploted on the PlotLayout
 
"ShowTitle" - show title "on" or "off"
 
"XAxisLabelName" - label ploted on the x-axis
 
"ShowXAxisLabel" - show x-axis label "on" or "off"
 
"ClickAndDragAlongX" - set the action along x-axis "on" or "off"
 
"ClickAndDragAlongY" - set the action along y-axis "on" or "off"
 
"YAxisLabelName" - label ploted on the y-axis
 
"ShowYAxisLabel" - show y-axis label "on" or "off"
 
"ShowGrid" - show grid "on" or "off"
 
"ShowLegend" - show legend "on" or "off"
 
"FontType" - global Font for the PlotLayout: "Arial", "Times", "Courier"
 
"TitleFontSize" - default: "20"
 
"AxisTitleFontSize" - default: "16"
 
"AxisLabelFontSize" - default: "12"
 
"LookupTable" colorNodeID default: "NULL"
 
 
NOTE: Setting the attribute Type will not update the Type of the PlotDataNode referenced by PlotChartNode. The method SetPlotType() has to be used.
 
  
 
= Signals =
 
= Signals =
Line 185: Line 173:
 
;void dataSelected(vtkStringArray* mrmlPlotDataIDs, vtkCollection* selectionCol)
 
;void dataSelected(vtkStringArray* mrmlPlotDataIDs, vtkCollection* selectionCol)
 
:Signal emitted when a data point or more has been selected. Returns the MRMLPlotDataNodes IDs and the correspective arrays with the data points ids (vtkIdTypeArray).
 
:Signal emitted when a data point or more has been selected. Returns the MRMLPlotDataNodes IDs and the correspective arrays with the data points ids (vtkIdTypeArray).
 +
 +
Python API example:
 +
 +
<pre lang="python">
 +
# Switch to a layout that contains a plot view to create a plot widget
 +
layoutManager = slicer.app.layoutManager()
 +
layoutWithPlot = slicer.modules.plots.logic().GetLayoutWithPlot(layoutManager.layout)
 +
layoutManager.setLayout(layoutWithPlot)
 +
 +
# Select chart in plot view
 +
plotWidget = layoutManager.plotWidget(0)
 +
plotViewNode = plotWidget.mrmlPlotViewNode()
 +
 +
# Add a PlotCharNode
 +
# plotViewNode.SetPlotChartNodeID(''PlotChartNode''.GetID())
 +
 +
# Connect the signal with a slot ''onDataSelected''
 +
plotView = plotWidget.plotView()
 +
plotView.connect("dataSelected(vtkStringArray*, vtkCollection*)", self.onDataSelected)
 +
 +
</pre>
  
 
= Future Work =
 
= Future Work =
Line 191: Line 200:
 
* More signals?
 
* More signals?
 
* Add 3D Plots (vtkChartXYZ)
 
* Add 3D Plots (vtkChartXYZ)
 +
* Add Click and Drag action for multiple selected points

Revision as of 07:34, 19 September 2018

Home < Documentation < Nightly < Developers < Plots


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


Slicer plotting overview and acknowledgements

Slicer provides Plotting facilities that include a plot view that can be displayed in the view layout, similarly to slice 3D views. Plot data is stored in table nodes, and plot series, chart, and view nodes define which table column need to be displayed and how. Plot can be serialized with the MRML scene, including the plot data and display properties. Plot series and charts can be created and edited in Plots module and plots can be also generated directly from Tables module by a single click.

Authors:
Davide Punzo (Kapteyn Astronomical Institute, University of Groningen)
Andras Lasso (PerkLab, Queen's University)

Contributors:
Jean-Christophe Fillion-Robin (Kitware)
Steve Pieper (Isomics)

Acknowledgements:
This work was supported by the European Research Council under the European Union's Seventh Framework Programme (FP/2007-2013)/ERC Grant Agreement nr. 291-531.

European Research Council Kapteyn Astronomical Institute

Contacts:

  • Davide Punzo, <email>punzodavide@hotmail.it</email>; <email>D.Punzo@astro.rug.nl</email>

Plot capabilities

  • Multiple plots types (Line, Bar, Scatter, Scatter bar), shown in standard view layouts.
  • Configurable chart and axis title, legend, grid lines.
  • Use indexes (0, 1, 2, ...) or a table column for X axis values.
  • Multiple plot series can be added to a single plot chart (even showing data from different tables, with different types - plot, bar), and the same series can be added to multiple charts. The same plot chart can be shown in any plot views (even simultaneously).
  • Label can be assigned to each data point (shown in tooltip when hovering over a data point).
  • Interactive editing of data points by drag-and-drop (data in referenced table nodes is updated).
  • Interactive selection of data points (rectangular or free-hand selection).
  • Plot data and display properties are stored in the MRML scene.
  • Plot view can be embedded into module user interfaces. Plot views can emit signals back to the application as the user interacts with a plot, which allows modules to perform additional processing on the selected data points.

What is the difference between Slicer Plot and Chart? See FAQ.

Shortcuts and Interactions

The Plot infrastructure allow the following interaction:

  • Left mouse button: depends on interaction mode of the view
    • Pan view: pan view
    • Select points: select points using rectangular selection
    • Freehand select points: select points using free-form selection
    • Move points: move data points by drag-and-drop; this changes values in the referenced table node
  • Middle mouse button: pan view (except in pan view mode; in that case it zooms to selected rectangular region)
  • Right mouse button: zoom in/out along X and Y axes
  • S: switch interaction mode (pan/select points/.../move points)
  • R: reset view to show all data series
  • U: unselect the points selection

Architecture

MRML Nodes

vtkMRMLTableNode
Table node stores values that specify data point positions or bar heights in the plots.
vtkMRMLPlotSeriesNode
Defines a data series by referring to a table node and column name(s) for X and Y axes and labels.
It also defines display properties, such as plot type, color, line style.
Line and bar plots only require Y axis (points along X axis are equally spaced), scatter plots require two input data columns, for X and Y axes.
vtkMRMLPlotChartNode
Specifies which data series need to be shown in the chart.
Also contains global display properties for the chart, such as titles and font style.
vtkMRMLPlotViewNode
Specifies which chart is to be displayed in the plot view and how the user can interact with it.
There has to be exactly one plot view node for each plot view widget. This class can not be created or copied unless is connected with a plot view.

Widgets

qMRMLPlotView
Displays a plot. It can be embedded into a module user interface.
qMRMLPlotWidget
Displays a plot and in a popup window a plot view controller widget plot view controller widget.
qMRMLPlotSeriesPropertiesWidget
Display/edit properties of a plot series node.
qMRMLPlotChartPropertiesWidget
Display/edit properties of a plot series node.
qMRMLPlotViewControllerWidget
Display/edit properties of a plot view node.

Constructing a plot

Below is an example in python to construct and display a plot communicating completely at the level of MRML. Note: this functionality is not available in Slicer 4.8, please use a recent SlicerPreview nightly build.

import slicer
import math

# Create table with x, cos, sin columns

tableNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
table = tableNode.GetTable()

arrX = vtk.vtkFloatArray()
arrX.SetName("x")
table.AddColumn(arrX)

arrY1 = vtk.vtkFloatArray()
arrY1.SetName("cos")
table.AddColumn(arrY1)

arrY2 = vtk.vtkFloatArray()
arrY2.SetName("sin")
table.AddColumn(arrY2)

# Fill in the table with some example values

import math
numPoints = 69
inc = 7.5 / (numPoints - 1)
table.SetNumberOfRows(numPoints)
for i in range(numPoints):
  table.SetValue(i, 0, i * inc )
  table.SetValue(i, 1, math.cos(i * inc))
  table.SetValue(i, 2, math.sin(i * inc))

# Create two plot series nodes

plotSeriesNode1 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotSeriesNode", "My first")
plotSeriesNode1.SetAndObserveTableNodeID(tableNode.GetID())
plotSeriesNode1.SetXColumnName("x")
plotSeriesNode1.SetYColumnName("cos")
plotSeriesNode1.SetPlotType(slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter)
plotSeriesNode1.SetLineStyle(slicer.vtkMRMLPlotSeriesNode.LineStyleNone)
plotSeriesNode1.SetMarkerStyle(slicer.vtkMRMLPlotSeriesNode.MarkerStyleSquare)
plotSeriesNode1.SetUniqueColor()

plotSeriesNode2 = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotSeriesNode", "My second")
plotSeriesNode2.SetAndObserveTableNodeID(tableNode.GetID())
plotSeriesNode2.SetXColumnName("x")
plotSeriesNode2.SetYColumnName("sin")
plotSeriesNode2.SetPlotType(slicer.vtkMRMLPlotSeriesNode.PlotTypeScatter)
plotSeriesNode2.SetUniqueColor()

# Create plot chart node

plotChartNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotChartNode")
plotChartNode.AddAndObservePlotSeriesNodeID(plotSeriesNode1.GetID())
plotChartNode.AddAndObservePlotSeriesNodeID(plotSeriesNode2.GetID())
plotChartNode.SetTitle('A simple plot with 2 curves')
plotChartNode.SetXAxisTitle('Something in x')
plotChartNode.SetYAxisTitle('Something in y')

# Switch to a layout that contains a plot view to create a plot widget

layoutManager = slicer.app.layoutManager()
layoutWithPlot = slicer.modules.plots.logic().GetLayoutWithPlot(layoutManager.layout)
layoutManager.setLayout(layoutWithPlot)

# Select chart in plot view

plotWidget = layoutManager.plotWidget(0)
plotViewNode = plotWidget.mrmlPlotViewNode()
plotViewNode.SetPlotChartNodeID(plotChartNode.GetID())

This code produces the plot below.

A simple plot.

Signals

PlotViews provide signals that allow Slicer to respond to user interactions with the Plot canvas:

void dataSelected(vtkStringArray* mrmlPlotDataIDs, vtkCollection* selectionCol)
Signal emitted when a data point or more has been selected. Returns the MRMLPlotDataNodes IDs and the correspective arrays with the data points ids (vtkIdTypeArray).

Python API example:

# Switch to a layout that contains a plot view to create a plot widget
layoutManager = slicer.app.layoutManager()
layoutWithPlot = slicer.modules.plots.logic().GetLayoutWithPlot(layoutManager.layout)
layoutManager.setLayout(layoutWithPlot)

# Select chart in plot view
plotWidget = layoutManager.plotWidget(0)
plotViewNode = plotWidget.mrmlPlotViewNode()

# Add a PlotCharNode 
# plotViewNode.SetPlotChartNodeID(''PlotChartNode''.GetID())

# Connect the signal with a slot ''onDataSelected''
plotView = plotWidget.plotView()
plotView.connect("dataSelected(vtkStringArray*, vtkCollection*)", self.onDataSelected) 

Future Work

  • Adding to VTKPlots the possibility to plot errorbars.
  • Add categorical and date labels to the Bar plotting (analogous to the CHART infrastructure)
  • More signals?
  • Add 3D Plots (vtkChartXYZ)
  • Add Click and Drag action for multiple selected points