How to change the colors of objects in VTK when using vtkAppendPolyData?

I’m trying to modify the color of each object that I’ve placed in a vtkAppendPolyData but I get weird colors. I mean the object is not in one color but each face of it has a different color.
Screenshot_2
I would like to have one color by object.
Here is the minimal example:

import vtk
sphereSource = vtk.vtkSphereSource()
sphereSource.SetCenter(5,0,0)
sphereSource.Update()
Colors = vtk.vtkUnsignedCharArray()
Colors.SetNumberOfComponents(3)
Cellarray = sphereSource.GetOutput().GetPolys().GetNumberOfCells()
Colors.SetNumberOfTuples(Cellarray)
for c in range(Cellarray):
    Colors.InsertNextTuple3(255, 0, 0)

sphereSource.GetOutput().GetCellData().SetScalars(Colors)
sphereSource.Update()


coneSource =vtk.vtkConeSource()
coneSource.Update()
Colors = vtk.vtkUnsignedCharArray()
Colors.SetNumberOfComponents(3)
Cellarray = coneSource.GetOutput().GetPolys().GetNumberOfCells()
Colors.SetNumberOfTuples(Cellarray)
for c in range(Cellarray):
    Colors.InsertNextTuple3(0, 255, 0)
coneSource.GetOutput().GetCellData().SetScalars(Colors)
coneSource.Update()

# Append the two meshes
appendFilter = vtk.vtkAppendPolyData()
appendFilter.AddInputData(sphereSource.GetOutput())
appendFilter.AddInputData(coneSource.GetOutput())

appendFilter.Update()

#  Remove any duplicate points.
cleanFilter = vtk.vtkCleanPolyData()
cleanFilter.SetInputConnection(appendFilter.GetOutputPort())
cleanFilter.Update()

# Create a mapper and actor
mapper = vtk.vtkPolyDataMapper()
# mapper.ScalarVisibilityOn()
mapper.SetInputConnection(cleanFilter.GetOutputPort())
mapper.SetColorModeToDirectScalars()

actor = vtk.vtkActor()
actor.SetMapper(mapper)

# Create a renderer, render window, and interactor
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)

# Add the actors to the scene
renderer.AddActor(actor)
renderer.SetBackground(.3, .2, .1) #  Background color dark red

# Render and interact
renderWindow.Render()
renderWindowInteractor.Start()

You handle the data arrays colors wrongly. You first allocate nTuples tuples (colors.SetNumberOfTuples()) and then insert new elements at the end of that array (colors.InsertNextTuple()). This way, you end up with an array of size 2*nTuples. The first half of tuples are not initialized (that’s why you see the funky color patterns), and the second half of tuples actually are red or green.

The solution: Either use InsertNextTuple(values) or SetNumberOfTuples(n) in combination with SetTuple(i, values), but never mix these two approaches.

The code:

import vtk

# Sphere in red.
sphereSource = vtk.vtkSphereSource()
sphereSource.SetCenter(5,0,0)
sphereSource.Update()
sphereSource = sphereSource.GetOutput() # vtkPolyData()

colors = vtk.vtkUnsignedCharArray()
colors.SetNumberOfComponents(3)
colors.SetNumberOfTuples(sphereSource.GetNumberOfCells())
for c in range(sphereSource.GetNumberOfCells()):
    colors.SetTuple(c, [255, 0, 0])
sphereSource.GetCellData().SetScalars(colors)

# Cone in green.
coneSource =vtk.vtkConeSource()
coneSource.Update()
coneSource = coneSource.GetOutput() # vtkPolyData()

colors = vtk.vtkUnsignedCharArray()
colors.SetNumberOfComponents(3)
colors.SetNumberOfTuples(coneSource.GetNumberOfCells())
for c in range(coneSource.GetNumberOfCells()):
    colors.SetTuple(c, [0, 255, 0])
coneSource.GetCellData().SetScalars(colors)

# Combine the two meshes
appendFilter = vtk.vtkAppendPolyData()
appendFilter.AddInputData(sphereSource)
appendFilter.AddInputData(coneSource)
appendFilter.Update()

# Create a mapper and actor
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(appendFilter.GetOutputPort())
mapper.SetColorModeToDirectScalars()

actor = vtk.vtkActor()
actor.SetMapper(mapper)

# Create a renderer, render window, and interactor
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)

# Add the actors to the scene
renderer.AddActor(actor)
renderer.SetBackground(.3, .2, .1) 

# Render and interact
renderWindow.Render()
renderWindowInteractor.Start()
1 Like

Okay. I get it.
I thought SetNumberOfTuples allocates the number of tuples I would like to have but I was wrong.
Thanks you so much !

SetNumberOfTuples does allocate the number tuples you want. But InsertNextTuple increases that number again. It’s fine to use either of those, but better don’t use them together.