python numpy VTKArray conversion in programmable filter

Hi all,

I am trying to convert a rotations tensor into a quaternion using a programmable filter. However, the actual conversion function from VTK refuses to cooperate…
The code:

from paraview.vtk.vtkCommonCore import vtkMath, vtkArray
from paraview.vtk.numpy_interface import dataset_adapter as dsa
import numpy as np
def make_quat(TENSOR):
    quatlist = [] 
    for t in TENSOR:
        quat = np.zeros(4)
        tens = np.asarray(t)
        #tens = np.asarray([[1,0,0],[0,1,0],[0,0,1]])
        print(type(tens), tens)
        vtkMath.Matrix3x3ToQuaternion(tens, quat)
        quatlist.append(quat) 
    o = np.asarray(quatlist).view(dsa.VTKArray)
    o.DataSet = TENSOR.DataSet
    o.Association = TENSOR.Association
    return o
tensor = inputs[0].PointData["TENSOR"]
output.PointData.append(make_quat(tensor), "test")

What I get is the following error message and output (yes, in that order):

Traceback (most recent call last):
File "<string>", line 22, in <module>
File "<string>", line 19, in RequestData
File "<string>", line 12, in make_quat
   TypeError: Matrix3x3ToQuaternion argument 1: expected a sequence of 3 values, got -1 values
<class 'numpy.ndarray'> [VTKArray([[ 0.70710678, -0.70710678,  0.        ], [ 0.70710678,  0.70710678,  0.        ], [ 0.        ,  0.        ,  1.        ]])]

Using the handcrafted tensor (commented), the whole filter works and give the expected results. Using that approach tens is also a “pure” numpy.ndarray, without nested VTKArray.

How do I correctly convert that VTKArray to be accepted by the conversion function?
Is that the actual problem or am I severely misunderstanding something else?

Hi,

maybe you can try to copy t (or tens) inside a new numpy array?
Actually VTKArray is a subclass of numpy.ndarray this error looks strange…

Hi,

As @nicolas.vuaille mentionned, VTKArray is a subclass of numpy.ndarray. Have you tried to use Matrix3x3ToQuaternion directly with t?

Then, I get exactly the same error.

Traceback (most recent call last):
  File "<string>", line 22, in <module>
  File "<string>", line 19, in RequestData
  File "<string>", line 12, in make_quat
TypeError: Matrix3x3ToQuaternion argument 1: expected a sequence of 3 values, got -1 values

For completeness, an example datafile and the STL file for the glyph I am testing this with:

data.vtp (4.6 KB)
sphere.stl (26.2 KB)

Here is how I solved the problem.

from paraview.vtk.vtkCommonCore import vtkMath, vtkArray
import vtk
import numpy as np

reader = vtk.vtkXMLPolyDataReader()
reader.SetFileName("data.vtp")
reader.Update()
point_data = reader.GetOutput().GetPointData()
specific_tensor_array = point_data.GetArray("TENSOR")
print(specific_tensor_array.GetNumberOfComponents())
for i in range(specific_tensor_array.GetNumberOfTuples()):
    print(specific_tensor_array.GetTuple(i))
    item = np.asarray(specific_tensor_array.GetTuple(i))
    print(item)
    tens = np.asarray([item[0:3],item[3:6],item[6:9]])
    print(tens)
    quat = np.zeros(4)
    vtkMath.Matrix3x3ToQuaternion(tens, quat)
    print(quat)

Here is the output:

python test.py  
9
(0.7071067811865475, 0.7071067811865476, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 1.0)
[ 0.70710678  0.70710678  0.         -0.70710678  0.70710678  0.
  0.          0.          1.        ]
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
[ 0.92387953  0.          0.         -0.38268343]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[1. 0. 0. 0. 1. 0. 0. 0. 1.]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 0. 0. 0.]
(0.7071067811865475, 0.7071067811865476, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 1.0)
[ 0.70710678  0.70710678  0.         -0.70710678  0.70710678  0.
  0.          0.          1.        ]
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
[ 0.92387953  0.          0.         -0.38268343]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[1. 0. 0. 0. 1. 0. 0. 0. 1.]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 0. 0. 0.]
(0.7071067811865475, 0.7071067811865476, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 1.0)
[ 0.70710678  0.70710678  0.         -0.70710678  0.70710678  0.
  0.          0.          1.        ]
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
[ 0.92387953  0.          0.         -0.38268343]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[1. 0. 0. 0. 1. 0. 0. 0. 1.]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 0. 0. 0.]
(0.7071067811865475, 0.7071067811865476, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 1.0)
[ 0.70710678  0.70710678  0.         -0.70710678  0.70710678  0.
  0.          0.          1.        ]
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
[ 0.92387953  0.          0.         -0.38268343]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[1. 0. 0. 0. 1. 0. 0. 0. 1.]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 0. 0. 0.]
(0.7071067811865475, 0.7071067811865476, 0.0, -0.7071067811865476, 0.7071067811865475, 0.0, 0.0, 0.0, 1.0)
[ 0.70710678  0.70710678  0.         -0.70710678  0.70710678  0.
  0.          0.          1.        ]
[[ 0.70710678  0.70710678  0.        ]
 [-0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]
[ 0.92387953  0.          0.         -0.38268343]
(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
[1. 0. 0. 0. 1. 0. 0. 0. 1.]
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
[1. 0. 0. 0.]

Thank you!
While this does not work in the PV programmable filter, it gave me the right ideas. This works:

from paraview.vtk.vtkCommonCore import vtkMath, vtkArray
from paraview.vtk.numpy_interface import dataset_adapter as dsa
import numpy as np
def make_quat(TENSOR):
    quatlist = []
    shape = np.shape(TENSOR)
    for i in range(shape[0]):
        quat = np.zeros(4)
        tens = TENSOR[i, :, :]
        vtkMath.Matrix3x3ToQuaternion(tens, quat)
        quatlist.append(quat) 
    o = np.asarray(quatlist).view(dsa.VTKArray)
    o.DataSet = TENSOR.DataSet
    o.Association = TENSOR.Association
    return o
tensor = inputs[0].PointData["TENSOR"].GetArrays()
output.PointData.append(make_quat(tensor[0]), "test")

What threw me off is that inputs[0].PointData["TENSOR"] returns a weird array shape with extra leading dimensions which I could not shave off. Adding a GetArrays() converts the leading dimension to a list (with only one element).
At least for me, this behavior was absolutely not intuitive.

1 Like