Set block color of a MultiBlockDataSet

I have a MultiBlockDataSet imported from a .vtm file. I am trying to set up specific colors for every block. My first attempt is to set the same color for every blocks but the color never changes.

Here is my Python code:

import vtkmodules.vtkRenderingOpenGL2 
from vtkmodules.vtkIOXML import vtkXMLMultiBlockDataReader
from vtkmodules.vtkFiltersGeometry import vtkGeometryFilter
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkCompositePolyDataMapper,
    vtkCompositeDataDisplayAttributes,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkCommonDataModel import vtkDataObjectTreeIterator

VTM_PATH = "viewable.vtm"

renderer = vtkRenderer()
renderer.SetBackground(0.2, 0.2, 0.2)

render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetSize(1200, 700)

reader = vtkXMLMultiBlockDataReader()
reader.SetFileName(VTM_PATH)
reader.Update()

geo_filter = vtkGeometryFilter()
geo_filter.SetInputConnection(reader.GetOutputPort())

mapper = vtkCompositePolyDataMapper()
mapper.SetInputConnection(geo_filter.GetOutputPort())
attributes = vtkCompositeDataDisplayAttributes()
mapper.SetCompositeDataDisplayAttributes(attributes)
actor = vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)


original_block_iterator = vtkDataObjectTreeIterator(
    data_set=reader.GetOutput(), visit_only_leaves=True, traverse_sub_tree=True)
original_block_iterator.InitTraversal()
while not original_block_iterator.IsDoneWithTraversal():
    original_block = original_block_iterator.GetCurrentDataObject()
    attributes.SetBlockColor(original_block, [0,1,1])
    original_block_iterator.GoToNextItem()

mapper.Modified()
mapper.Update()

renderer.ResetCamera()

interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
style = vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
render_window.Render()
interactor.Start()

Here is the result:

Maybe I am not using the MultiBlockDataSet correctly.

Thanks for the help

1 Like

In your pipeline, the output of geo_filter is passed to the mapper, so pass that output to the block iterator.

Here’s code. I cleaned it up a bit. Removed unneded calls to Modified() and Update(). See new code with the comment # NEW

import vtkmodules.vtkRenderingOpenGL2 
from vtkmodules.vtkIOXML import vtkXMLMultiBlockDataReader
from vtkmodules.vtkFiltersGeometry import vtkGeometryFilter
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkCompositePolyDataMapper,
    vtkCompositeDataDisplayAttributes,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkCommonDataModel import vtkDataObjectTreeIterator

VTM_PATH = "viewable.vtm"

renderer = vtkRenderer()
renderer.SetBackground(0.2, 0.2, 0.2)

render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetSize(1200, 700)

reader = vtkXMLMultiBlockDataReader()
reader.SetFileName(VTM_PATH)

geo_filter = vtkGeometryFilter()
geo_filter.SetInputConnection(reader.GetOutputPort())
geo_filter.Update()

# NEW
geometry_output = geo_filter.GetOutput()

mapper = vtkCompositePolyDataMapper()
mapper.SetInputConnection(geometry_output) # NEW
attributes = vtkCompositeDataDisplayAttributes()
mapper.SetCompositeDataDisplayAttributes(attributes)
actor = vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)

original_block_iterator = vtkDataObjectTreeIterator(
    data_set=geometry_output, # NEW
    visit_only_leaves=True, traverse_sub_tree=True)
original_block_iterator.InitTraversal()
while not original_block_iterator.IsDoneWithTraversal():
    original_block = original_block_iterator.GetCurrentDataObject()
    attributes.SetBlockColor(original_block, [0,1,1])
    original_block_iterator.GoToNextItem()

renderer.ResetCamera()

interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
style = vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
render_window.Render()
interactor.Start()

Thanks so much for the fast answer!!

Indeed, I need to use the output of the geometry filter to have to correct dataset for the traverse.

However, it does not change the resulting image.

I also need to leave the mapper.SetInputConnection(geo_filter.GetOutputPort()) since the mapper want an input connection.

sorry, this should be mapper.SetInputData(geometry_output)

I also tried that but I got the same error:

vtkCompositeDataPipeline (0x31ffd870): Input port 0 of algorithm vtkCompositePolyDataMapper (0x32012040) has 0 connections but is not optional.

okay. it complains because GetOutput returns a vtkPolyData but in your case we want a vtkCompositeDataSet. Replace GetOutput with GetOutputDataObject, and SetInputData with SetInputDataObject.

Full code that should work (tested on my end)

import vtkmodules.vtkRenderingOpenGL2 
from vtkmodules.vtkIOXML import vtkXMLMultiBlockDataReader
from vtkmodules.vtkFiltersGeometry import vtkGeometryFilter
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkCompositePolyDataMapper,
    vtkCompositeDataDisplayAttributes,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
)
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkCommonDataModel import vtkDataObjectTreeIterator

VTM_PATH = "viewable.vtm"

renderer = vtkRenderer()
renderer.SetBackground(0.2, 0.2, 0.2)

render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetSize(1200, 700)

reader = vtkXMLMultiBlockDataReader()
reader.SetFileName(VTM_PATH)

geo_filter = vtkGeometryFilter()
geo_filter.SetInputConnection(reader.GetOutputPort())
geo_filter.Update()

# NEW
geometry_output = geo_filter.GetOutputDataObject(0)

mapper = vtkCompositePolyDataMapper()
mapper.SetInputDataObject(geometry_output) # NEW
attributes = vtkCompositeDataDisplayAttributes()
mapper.SetCompositeDataDisplayAttributes(attributes)
actor = vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)

original_block_iterator = vtkDataObjectTreeIterator(
    data_set=geometry_output, # NEW
    visit_only_leaves=True, traverse_sub_tree=True)
original_block_iterator.InitTraversal()
while not original_block_iterator.IsDoneWithTraversal():
    original_block = original_block_iterator.GetCurrentDataObject()
    attributes.SetBlockColor(original_block, [0,1,1])
    original_block_iterator.GoToNextItem()

renderer.ResetCamera()

interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
style = vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
render_window.Render()
interactor.Start()

Thanks it is working.

Can you explain why I need to get the data out from the filter and not directly connect the algorithm connection output? Looks counter intuitive with the classic vtk pipeline.

the vtkCompositeDataDisplayAttributes needs the data object.

You can still make a pipeline connection. Just ensure that the data objects passed in attributes.SetBlockColor are valid datasets that are rendered by the mapper.