Help with Python Plugin Filter using VTKPythonAlgorithmBase approach

I am trying to use the VTKPythonAlgorithmBase approach to create a custom filter plugin that will send the filter output back to the ParaView pipeline.

I’ve adopted the “Half V Filter” example in the chapter 12.4 of the ParaView guide for my particular dataset:

from vtkmodules.vtkCommonDataModel import vtkDataSet
from vtkmodules.util.vtkAlgorithm import VTKPythonAlgorithmBase
from vtkmodules.numpy_interface import dataset_adapter as dsa
from paraview.util.vtkAlgorithm import smproxy, smproperty, smdomain

@smproxy.filter(label="Half ID Filter")
@smproperty.input(name="Input")
class HalfIDFilter(VTKPythonAlgorithmBase):
    def __init__(self):
        VTKPythonAlgorithmBase.__init__(self)
    def RequestData(self, request, inInfo, outInfo):
        input0 = dsa.WrapDataObject(vtkDataSet.GetData(inInfo[0]))
        data = input0.CellData["ID"]/2.0
        output = dsa.WrapDataObject(vtkDataSet.GetData(outInfo))
        output.CellData.append(data, "ID_half")
        return 1

The above filter is applied to a data set that has been loaded into the pipeline. The data set contains cell data named “ID”. I’m hoping to apply this filter and get a new cell data entry named “ID_half”.

Currently, I am able to load the filter and apply it. However, nothing is outputted into the pipeline.

Thank you,
Victor

That certainly looks reasonable to me. It’s not obvious, but if you add ‘print’ statements to your filters, you can see them in the Output window.
In my filter, I was unable to use vtkDataSet.GetData(outInfo), I had to use a more specific type like vtkPolyData, but the example clearly uses vtkDataSet, and I’m not using numpy.

I suggest adding print(output) to see if it’s doing what you want.

HTH,

Aron

Hi Aron,
When printing the output in the custom filter above, I see

<vtkmodules.numpy_interface.dataset_adapter.PolyData object at ...>

However, when I do the same in the following programmable filter (which accomplishes what I’m hoping for in the above custom filter):

input0 = inputs[0]
data = input0.CellData["ID"]/2.0
output.CellData.append(data, "ID_half")
print(output)

I get

<vtkmodules.numpy_interface.dataset_adapter.UnstructuredGrid object at ...>

I notice that in the custom filter, output is a PolyData object, while in the programmable filter, output is an UnstructuredGrid object. I wonder if this is the reason the output is not sent back to the ParaView data pipeline.

Is there a way to make the outInfo variable in RequestData(...) to be the same type of object as the input, i.e., an UnstructuredGrid object?

Thanks,
Victor

Hi Victor,
If you go back to the ParaView Guide 12.4, you’ll see some of the examples specify the output type:

VTKPythonAlgorithmBase.init(self, nInputPorts=1, nOutputPorts=1, outputType=“vtkUnstructuredGrid” )

Hopefully that will fix your problem.

Regards,

Aron

Hi Aron,
Making the object type consistent did not solve the problem. I still cannot access the output data in the ParaView data pipeline. I have rewritten the custom filter as follows:

from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkUnstructuredGrid
from vtkmodules.util.vtkAlgorithm import VTKPythonAlgorithmBase
from vtkmodules.numpy_interface import dataset_adapter as dsa
from paraview.util.vtkAlgorithm import smproxy, smproperty, smdomain

@smproxy.filter(label="Half ID Filter")
@smproperty.input(name="Input")
class HalfIDFilter(VTKPythonAlgorithmBase):
    def __init__(self):
        VTKPythonAlgorithmBase.__init__(self, 
                                        nInputPorts=1, 
                                        nOutputPorts=1, 
                                        outputType="vtkUnstructuredGrid")
    def RequestData(self, request, inInfo, outInfo):
        input0 = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(inInfo[0]))
        data = input0.CellData["ID"]/2.0
        output = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(outInfo))
        output.CellData.append(data, "ID_half")
        print("output object = ", output)
        print("output keys = ", output.CellData.keys())
        print("output data = ", output.CellData["ID_half"])
        return 1

Note that all the vtkDataSet calls have now been switched to vtkUnstructuredGrid. The output in the output window when applying the filter is

('output object = ', <vtkmodules.numpy_interface.dataset_adapter.UnstructuredGrid object at ... >)
('output keys = ', ['ID_half'])
('output data = ', VTKArray([], shape=(0L, 534L), dtype=float64)

As seen from the output, the object type is UnstructuredGrid, the "ID_half" key has been added, but the data in the output object is empty.

Thanks,
Victor

I’m pretty sure you can fix this problem by adding this just after output is defined:
output.ShallowCopy(input0)

I’m not sure why the example from the ParaView guide doesn’t include this, too.

Regards,

Aron

Hi Aron,
The shallow copy did the job of exposing the output of the filter to the ParaView data pipeline. I ended up performing the shallow copy before the append call as follows:

output = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(outInfo))
output.ShallowCopy(vtkUnstructuredGrid.GetData(inInfo[0]))
output.CellData.append(data, "ID_half")

However, wouldn’t the shallow copy end up doubling my memory footprint? Is there a way to only expose the newly created data set.

Thanks,
Victor

No, it won’t increase your memory footprint - that is the purpose of ShallowCopy (instead of DeepCopy). The output will use references to all the input data structures, except for the one ID_half array you have added to the output data.

Got it. Thank you for all your help Aron!