Operating system: Windows 7 Enterprise 64-bit (6.1, Build 7601)
Slicer version: version 4.10.2 revision 28257 built 2019-05-22
Expected behavior:
I am using the MultiVolumeExporer to extract a time intensity curve of a DCE MRI scan. To do this, I made a segmentation of the tumor and created a chart of the signal intensity over time.
There are actually 2 features that I would like.
to access the raw extracted data values (i.e. the mean signal intensity over time)
to save the chart that was created as an SVG such that I can use it in full resolution.
Actual behavior:
the raw values are stored in a node that I am not able to access.
I am not able to save the chart other than saving it a snapshot.
I tried to save the chart in the following manner:
e = vtk.vtkGL2PSExporter()
e.SetFileFormatToSVG()
lm = slicer.app.layoutManager()
e.SetRenderWindow(lm.plotWidget(1).plotView())
e.SetFilePrefix(‘D:/pre’)
e.Update()
When I do this I get the following error message:
“TypeError: SetRenderWindow argument 1: method requires a VTK object”
I understand from this that the plotView apparently isn’t a VTK object. However I have no clue about how to change this or why it did seem to work in the above mentioned topic on chart exporting.
Also I tried to use the saveAsSVG function that war implemented in the above mentioned commit, however it does not seem to be available in slicer 4.10.2. I tried to use the slicer nightly build instead, however the MultiVolumeExplorer in the nightly doesn’t work as expected and doesn’t provide a chart.
Ah, okay I obviously don’t need the plotWidget but need to access the chartWidget and get it’s renderer.
However unlike the sliceWidget, the chartWidget doesn’t have a lm.chartWidget(1).chartView().renderWindow()…
How do I access the renderer to pass it onto the exporter??
Ok, I didn’t know this but apparently you need to access the mrmlScene nodes and not the layoutManager nodes. I got the data out in the following manner:
# My goal is to get the datapoints from 'Chart_6'
n = slicer.mrmlScene.GetNodesByName('Chart_6')
for nn in n:
print(nn) # Apparently only one node available
# Get the names of the data series in this node
for i in range(nn.GetArrayNames().GetNumberOfValues()):
print(nn.GetArrayNames().GetValue(i))
# I want to have the series that is named 'tissue'
a_node_name = nn.GetArray('tissue')
a_MRML_node = slicer.mrmlScene.GetNodeByID(a_node_name)
a_vtk_node = a_MRML_node.GetArray()
data = [a_vtk_node.GetValue(e) for e in range(a_vtk_node.GetNumberOfValues())]
So I got the chart data which allows me to plot the graph myself. But still I think it should be possible to get the actual render itself. Can someone help me do this?
You can get numpy array from a volume node using a single command: slicer.util.arrayFromVolume.
VTK plotting is extremely fast and allows rich interactions. VTK should be able to produce SVG plots, too, but probably it is simpler to just use matplotlib.
A complete example that gets voxels of an MRI volume as numpy array, computes histogram, draws a plot, saves as svg, and display it in a web view:
# Get a volume from SampleData and compute its histogram
import SampleData
import numpy as np
volumeNode = SampleData.SampleDataLogic().downloadMRHead()
volumeVoxels = slicer.util.arrayFromVolume(volumeNode)
histogram = np.histogram(volumeVoxels, bins=50)
# Make sure matplotlib is installed
try:
import matplotlib
except ModuleNotFoundError:
pip_install('matplotlib')
import matplotlib
matplotlib.use('Agg')
# Show a plot using matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(histogram[1][1:], histogram[0].astype(float))
ax.grid(True)
ax.set_ylim((0, 4e5))
outputFilePath = slicer.app.temporaryPath+'/test.svg'
plt.savefig(outputFilePath)
# Show the saved svg file in a web view window
webView = slicer.qSlicerWebWidget()
webView.url = qt.QUrl().fromLocalFile(outputFilePath)
webView.show()