MRML table nodes disconnecting from table view when switching layouts

In my scripted module, I have two mrml table nodes saved as variables. When data is loaded from a server, the table nodes are modified and the changes are displayed. This works normally until the user switches to another module and back to my module. The table nodes still exist inside slicer; however, the table displays no data and the table views’ table node is set to None. The code can for table node creation and connection to the table view can be found here.

My first question is this intended functionality or is the way I am using table nodes incorrect?

I was able to find a workaround for this issue by using the enter function to reconnect the table node to the table view. Assuming the interaction described above is intended, is this the proper way to handle table node re-connection?

Below is a small script you can run to reproduce this issue.

    layoutManager = slicer.app.layoutManager()
    layoutManager.setLayout(35)
    
    table_node = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
    table_node.SetName("TestName")
    
    col1 = vtk.vtkStringArray()
    col1.SetName("Column 1")
    col1.InsertNextValue("Test1")
    
    col2 = vtk.vtkStringArray()
    col2.SetName("Column 2")
    col2.InsertNextValue("Test2")
    
    table_node.AddColumn(col1)
    table_node.AddColumn(col2)
    
    layoutManager.tableWidget(0).tableView().setMRMLTableNode(table_node)
1 Like

Updated the script and added two images showing the expected table and actual table after the layout switch.

layoutManager = slicer.app.layoutManager()
layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayout3DTableView)

table_node = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode")
table_node.SetName("TestName")

col1 = vtk.vtkStringArray()
col1.SetName("Column 1")
col1.InsertNextValue("Test1")

col2 = vtk.vtkStringArray()
col2.SetName("Column 2")
col2.InsertNextValue("Test2")

table_node.AddColumn(col1)
table_node.AddColumn(col2)

layoutManager.tableWidget(0).tableView().setMRMLTableNode(table_node)

# Switch to a layout without table view
layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutCompareGridView)

# Switch back to a layout with the table view
layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayout3DTableView)
Expected Actual
1 Like

Thank you, this script made it very easy to reproduce the unexpected behavior and see what was wrong.

This line accesses a low-level widget property and changes which table is shown in the table view:

layoutManager.tableWidget(0).tableView().setMRMLTableNode(table_node)

However, this property is controlled by nodes in the scene. As soon as the window is refreshed, the property is set again from the scene.

You need to set the displayed node in the table view node like this:

 layoutManager.tableWidget(0).tableView().mrmlTableViewNode().SetTableNodeID(table_node.GetID())

The syntax could be a bit simpler, but the mrmlTableViewNode method was not exposed in the table widget. I’ve updated the Python wrapping and from tomorrow this will work, too (in Slicer Preview Releases):

layoutManager.tableWidget(0).mrmlTableViewNode().SetTableNodeID(table_node.GetID())
1 Like

That solves the issue perfectly. Thanks!