-
-
Save jcfr/4ed6b66389c081d72b9a5793b352df76 to your computer and use it in GitHub Desktop.
use a class to manage the nodes involved in a slicer plot view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# To try this example, save this to a file slicer_plot_data.py, then execute Slicer from the command line | |
# with the arguments `--python-script slicer_plot_data.py`. | |
import qt | |
import vtk | |
import slicer | |
class SlicerPlotData: | |
"""Container for and manager of the nodes associated to a slicer plot view.""" | |
# A plot view node we will keep empty in order to have a way of displaying no plot | |
empty_plot_view_node = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotViewNode", "SlicerPlotDataEmptyPlotViewNode") | |
def __init__(self, name:str): | |
"""Create SlicerPlotData, making a qMRMLPlotView and a vtkMRMLPlotViewNode with the given name.""" | |
self.name = name | |
self.plot_view = slicer.qMRMLPlotView() | |
self.plot_view.setMRMLScene(slicer.mrmlScene) | |
self.plot_view_node = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotViewNode", name+"PlotView") | |
self.plot_view.setMRMLPlotViewNode(self.plot_view_node) | |
self.plot_nodes = {} # chart, table, and series; see the parameter "nodes" in the doc of slicer.util.plot | |
def set_plot_data(self, data, x_axis_label=None, y_axis_label=None, title=None, legend_label=None, plot_type="Line", labels=None): | |
""" | |
Populate the plot with the data from the given numpy array. | |
Args: | |
data: a numpy array of shape (N,2) containing the data to plot | |
x_axis_label: the title of the x-axis to display | |
y_axis_label: the title of the y-axis to display | |
title: plot title; also shows up in the names of helper nodes | |
legend_label: the text to put in the legend | |
plot_type: one of "Line", "Bar", "Scatter", or "ScatterBar" | |
labels: a list of string labels-- this affects Bar and ScatterBar plot types | |
""" | |
if title is None: | |
title = self.name | |
if legend_label is None: | |
legend_label = title | |
if len(data.shape) != 2 or data.shape[1] != 2: | |
raise ValueError(f"data was expected to be a numpy array of shape (N,2), got {tuple(data.shape)}") | |
# Here we avoid changing plots while they are associated to a plot view. | |
# This is to supress an error that otherwise shows up | |
# (see e.g. https://github.com/KitwareMedical/lungair-desktop-application/issues/27). | |
self.plot_view.setMRMLPlotViewNode(self.empty_plot_view_node) | |
if x_axis_label is not None and y_axis_label is not None: | |
columnNames = [x_axis_label, y_axis_label] | |
else: | |
columnNames = None | |
plot_chart_node = slicer.util.plot( | |
data, 0, show = False, | |
title = title, | |
columnNames = columnNames, | |
nodes = self.plot_nodes, | |
) | |
if x_axis_label is not None: | |
plot_chart_node.SetXAxisTitle(x_axis_label) | |
if y_axis_label is not None: | |
plot_chart_node.SetYAxisTitle(y_axis_label)GetPlotTypeAsString | |
assert(len(self.plot_nodes["series"]) == 1) | |
self.plot_nodes["series"][0].SetName(legend_label) # This text is displayed in the legend | |
self.plot_nodes["series"][0].SetPlotType(slicer.vtkMRMLPlotSeriesNode.GetPlotTypeFromString(plot_type)) | |
self.plot_view_node.SetPlotChartNodeID(plot_chart_node.GetID()) | |
if labels is not None: | |
labels_array = vtk.vtkStringArray() | |
for label in labels: | |
labels_array.InsertNextValue(label) | |
label_column_name = (x_axis_label if x_axis_label else "X-axis") + " Label" | |
labels_array.SetName(label_column_name) | |
self.plot_nodes['table'].AddColumn(labels_array) | |
self.plot_nodes["series"][0].SetLabelColumnName(label_column_name) | |
self.plot_view.setMRMLPlotViewNode(self.plot_view_node) | |
#------------------------------------------ | |
# Example usage | |
#------------------------------------------ | |
import numpy as np | |
slicer_plot_data = SlicerPlotData("example plot") | |
slicer_plot_data.set_plot_data(np.random.normal(size=(10,2))) | |
# Now you can put the widget slicer_plot_data.plot_view wherever you want. Here we just show it on its own: | |
slicer_plot_data.plot_view.show() | |
# (Note that for proper cleanup when exiting the application, the plot_view widget should really be parented to something.) | |
# Use set_plot_data to update what is shown in the plot view: | |
slicer_plot_data.set_plot_data(np.random.normal(size=(10,2))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment