Separate colour maps for multiple representations in single render view in custom application

I have a custom Paraview application that is used to display astronomical data. As part of it, I display multiple 2D images in the same renderview (an instance of pqRenderView*). The images are all instantiated and loaded separately, to make sure that arbitrary numbers of images can be loaded.

The images are created as follows:

imageRep = builder->createDataRepresentation(this->imageSource->getOutputPort(0), viewImage);
imageProxy = imageRep->getProxy();
vtkSMPropertyHelper(imageProxy, "Representation").Set("Slice");
auto separateProperty = vtkSMPVRepresentationProxy::SafeDownCast(imageProxy)->GetProperty("UseSeparateColorMap");
vtkSMPropertyHelper(separateProperty).Set(1);
vtkSMPVRepresentationProxy::SetScalarColoring(imageProxy, "FITSImage", vtkDataObject::POINT);
imageProxy->UpdateVTKObjects();

The colour map for each image is initialised by the following:

// Set up colour map controls
vtkNew<vtkSMTransferFunctionManager> mgr;
lutProxy = vtkSMTransferFunctionProxy::SafeDownCast(mgr->GetColorTransferFunction("FITSImage", imageProxy->GetSessionProxyManager()));

When the user changes the colour map, this is what I use to change the colour map:

if (vtkSMProperty *lutProperty = imageProxy->GetProperty("LookupTable")) {
    auto presets = vtkSMTransferFunctionPresets::GetInstance();
    lutProxy->ApplyPreset(presets->GetFirstPresetWithName(name.toStdString().c_str()));
    vtkSMPropertyHelper(lutProperty).Set(lutProxy);
    lutProxy->UpdateVTKObjects();
    vtkSMPVRepresentationProxy::RescaleTransferFunctionToDataRange(imageProxy, false, false);

    vtkSMPVRepresentationProxy::SetScalarBarVisibility(imageProxy, viewImage->getProxy(), true);

    imageProxy->UpdateVTKObjects();
    this->colourMap = name;
    return 1;
}

If the user chooses to select log scale, that is changed by this snippet:

if (auto logProperty = lutProxy->GetProperty("UseLogScale"))
{
    double range[2];
    vtkSMTransferFunctionProxy::GetRange(lutProxy, range);
    vtkSMCoreUtilities::AdjustRangeForLog(range);

    this->logScale = true;
    vtkSMTransferFunctionProxy::RescaleTransferFunction(lutProxy, range);
    vtkSMPropertyHelper(logProperty).Set(1);
    changeColorMap(this->getColourMap());

    lutProxy->UpdateVTKObjects();
    imageProxy->UpdateVTKObjects();
    return 1;
}

For some reason, if I just change the log scaling property, the actual colour map resets to the default, which is why I change the colour map again after setting the scaling property.

Each image is initialised separately and added to the pqRenderView. However, despite setting the “UseSeparateColorMap” property to true on initialising the image, all the images in the renderview has their colour maps synchronised. If any of the images have their colour maps changed, all the others will follow suit.

What am I missing here?

This is exactly what should fix the issue you are describing.

You may want to try to reproduce the issue in ParaView proper and check the property is actually set in your application.

In the Paraview client the "UseSeparateColourMap" button works as expected. When I check the value of the "UseSeparateColourMap" property in my application, it returns 1 (as expected). I use the following code to check:

int sep;
vtkSMPropertyHelper(vtkSMPVRepresentationProxy::SafeDownCast(imageProxy)->GetProperty("UseSeparateColorMap")).Get(&sep);
if (sep == 1)
    std::cerr << "Setting colour map with \"UseSeparateColourMap\" set to true!" << std::endl;

This returns true at every point after I set it first (see my first post on this topic for that detail). Note that this is all on the client side, I do not know how I can check a property value on the server side.

Client/Server should not matter.

Sounds like a bug, could you open an issue ?
https://gitlab.kitware.com/paraview/paraview/-/issues

Reported as issue #22305: https://gitlab.kitware.com/paraview/paraview/-/issues/22305

We have stumbled on a solution or workaround, but we don’t know what the intended behaviour is. We previously declared the lutProxy (which handles the colour map) as below:

vtkNew<vtkSMTransferFunctionManager> mgr;
lutProxy = vtkSMTransferFunctionProxy::SafeDownCast(mgr->GetColorTransferFunction("FITSImage", imageProxy->GetSessionProxyManager()));

Note the arguments when we call the GetColorTransferFunction: mgr->GetColorTransferFunction("FITSImage", imageProxy->GetSessionProxyManager()));.

All images had their lutProxies named the same, "FITSImage". By adding a unique number to the name (e.g., "FITSImage_k" for the kth image), we now have correct behaviour in the view (i.e., different images can have different colour mappings). I do not know if this is intended behaviour or if the previous version overrode the “UseSeparateColorMap” property.