DataArray example

A seemingly basic question, that I could not find an example for: I am trying to visualize finite-element analysis results in which I have PolyData (triangular elements) and nodal scalar output.
I can successfully create points and cells but then get confused adding scalar data associated with points. Specifically when I try to create a new instance of dataArray, like this: let array1 = vtk.Common.Core.vtkDataArray.newInstance(); I get an exception. Here’s the code example:
https://jsfiddle.net/k_udilovich/r3joqg74/30/
Ideally I would like the type of color map similar to the Calculator example (https://kitware.github.io/vtk-js/examples/Calculator.html ) but provide scalar values via an array rather than using a formula filter. Would it be possible to get a pointer to a complete example? Thanks

vtkDataArray is an abstract class. You need to decide which value type you want to store, and instantiate this one. For instance, you can instantiate a vtkDoubleArray.

Then, if you want to map this vtkDataArray to points in your vtkPolyData, you should give it a name (vtkDataArray::SetName), and add it using vtkPolyData::GetPointData::AddArray.

Thanks a lot, Yohann. It looks like your response is for C++. Would the same apply to vtk.js? If so, could you give a Javascript example, please?

Call vtk.Common.Core.vtkDoubleArray.newInstance(), and then I’m not really sure how to add an array… I don’t have much experience with vtk.js. Given your polydata that I’ll call pd and a data array that I’ll call array, try pd.getPointData().addArray(array) ?

Thanks Yohann. There still seems to be a problem with newInstance() call, even though I am using vtkDoubleArray class instead of the abstract one. I have updated the example here: https://jsfiddle.net/k_udilovich/r3joqg74/34/, its on line 71.

I might have put you in the wrong direction. Looking at ab example on the web, it seems that vtkDataArray can be directly instantiated in vtk.js. Did you import vtkDataArray like in this example?

Yes, I have tried to do it as shown in this example.
I am thinking that another relevant example is this one:
https://kitware.github.io/vtk-js/examples/ScalarToRGBA.html
However, I am still not clear how to “supply” scalar data associated with points. The examples with PlaneSource use formula filters and such to specify the numerical data, and my objective is to read that information as an array from an external source.

In vtk.js you can not create an empty vtkDataArray unless you state it explicitly.

const emptyArray = vtkDataArray.newInstance({ empty: true });
const values = new Float32Array(size * 3);
emptyArray.setData(values, 3);
emptyArray.setName('velocity')

or better

const values = new Float32Array(size * 3);
const filledArray = vtkDataArray.newInstance({ name: 'velocity', values, numberOfComponents: 3 });

polydata.getPointData().addArray(filledArray); // AddArray is for the C++ not the JS

Thanks, Sebastien, it makes total sense. However, I am still getting the same stubborn error both in my JSFiddle example (https://jsfiddle.net/k_udilovich/r3joqg74/43/) and in the production code:
"ERROR TypeError: “vtk_js_Sources_Common_Core__WEBPACK_IMPORTED_MODULE_13__.default.newInstance is not a function”

How do you import vtk.js? Because your code seems fine.

The only thing that is weird in your end goal below is the use of field while getCellData/getPointData/getFieldData that would dictate to which part of your mesh that field is supposed to be linked to. Also you can have only 1 scalar per Point/Cell. It might be better to just do AddArray and configure the mapper to select which one you want to see in case you have more than 1.

  polydata.getCellData().setScalars( vtkDataArray.newInstance({
     name: 'var1',
     field: FieldDataTypes.POINT
     values: Float32Array.from(valuesArray)
 }));

Sebastien,
I am bringing vtk.js via npm in the production code. This is package.json part:
“vtk.js”: “^14.15.4”,
“worker-loader”: “^3.0.1”
In jsfifddle it’s the CDN (latest version): https://unpkg.com/vtk.js@18.1.12/vtk.js
The “field” entry in the .setScalars() call is probably wrong. I will remove it. So as long as your example above (with ‘velocity’) field works it would satisfy my requirements. Unfortunately it seems like vtkDataArray.newInstance() call is what crashing the code at the moment.

This should work

const filledArray = vtk.Common.Core.vtkDataArray.newInstance({ name: 'velocity', values });
polydata.getPointData().addArray(filledArray);

Thanks a lot Sebastien!
This worked in JSFiddle, which uses version 18.1.12 but it unfortunately didn’t work in version 14.15.4 (in production Angular code) I’ll try to see if I can update my solution, unfortunately when I used later versions some of the examples (like the calculator one) stopped working. Thanks again for your help.

Something else is going on as this is core code and that part did not change and should work out of the box.

Could you be more explicit on which part is not working (error message) with 14.15.4?

Sebastien, After struggling with different versions in Angular, I have rebuilt the test in Vue and it works perfectly, at least the vtkDataArray.newInstance call. There’s something fishy with trying to use Vtk.js with Angular. However, to answer your question the error I’ve been getting before switching over to Vue was always the same: "ERROR TypeError: “vtk_js_Sources_Common_Core__WEBPACK_IMPORTED_MODULE_13__.default.newInstance is not a function” even when I used the working solution with non-empty instantiation of dataArray. The issue might be related to Angular, which I gave up on, but even in JSFiddle when I changed the version to 14.15.4 I got “Uncaught ReferenceError: vtkDataArray is not defined”, which goes away when upgrading to version 18.

Thanks for the update. This is so weird. I’m not sure how vtkDataArray is not defined in the 14.15.4 version. But ok. At least, if it is working for you finally that is great.

Thanks for your patience Sebastien! So moving on to the final step of my prototype: Trying to map the scalar data in polydata onto the cells. I feel like I am missing a step. Here’s what I am doing:

//Color range
const lookupTable = vtkLookupTable.newInstance({ hueRange: [1, 0] });
lookupTable.setMappingRange(0,1);
const { ColorMode, ScalarMode } = vtkMapper;
const { FieldDataTypes } = vtkDataSet;
const mapper = vtkMapper.newInstance({
interpolateScalarsBeforeMapping: true,
colorMode: ColorMode.DEFAULT,
scalarMode: ScalarMode.DEFAULT,
useLookupTableScalarRange: true,
lookupTable,});
 //filter
const rgbaFilter = vtkScalarToRGBA.newInstance();
rgbaFilter.setLookupTable(lookupTable);
rgbaFilter.setInputConnection(polydata.getOutputPort());
mapper.setInputConnection(rgbaFilter.getOutputPort());
actor.setMapper(mapper);

The line:

rgbaFilter.setInputConnection(polydata.getOutputPort());

is failing. Polydata does not have this method. I am confused how to connect the polydata to the rgbaFilter.

First you don’t need vtkScalarToRGBA since that filter is to create a texture. You don’t need a texture. You just need to tell the mapper to show which ever array you want to look at.

Then you have a dataset not an vtkAlgorithm. A vtkAlgorithm will produce dynamically the underlying dataset. Since your stuff is static, you just need to do.

const polydata = ...;
mapper.setInputData(polydata);
actor.setMapper(mapper);
renderer.addActor(actor);

Many thanks. As you probably guessed I have no prior experience with VTK, so I’m most likely doing some dumb things. I’ve updated my JSFiddle.
https://jsfiddle.net/k_udilovich/r3joqg74/89/
No errors now, but the color-coded visual as I expected with colors driven by nodal scalars still doesn’t show up. Sorry about being such a pest :pensive:

image

I don’t see anything rendering in your jsfiddle. But if it is only the color missing, then it is just a matter to properly configuring your mapper. We do that dynamically here from that example.