vtkGradientFilter: no input array?

I’ve written a C++ application that reads and displays topographic data from a file.
For the data source I’ve subclassed vtkAbstractPolyDataReader to TopoGridReader. TopoGridReader::GetOutput() contains a vtkPoints object and a vtkCellArray object, with data type double. My app displays the topography, now I want to display the topographic slope.
I connect a vtkGradientFilter to my TopoGridReader:

gridReader->Update();
gradientFilter->SetInputConnection(gridReader->GetOutputPort());
gradientFilter->Update();

However on calling gradientFilter->Update() the application emits this error:

024-11-19 16:47:07.658 (  72.809s) [    7FFF9F7FE640]  vtkGradientFilter.cxx:290    ERR| vtkGradientFilter (0x7fff9043bc50): No input array. If this dataset is part of a composite dataset check to make sure that all non-empty blocks have this array.
2024-11-19 16:47:07.659 (  72.809s) [    7FFF9F7FE640]       vtkExecutive.cxx:729    ERR| vtkCompositeDataPipeline (0x7fff91a3e220): Algorithm vtkGradientFilter (0x7fff9043bc50) returned failure for request: vtkInformation (0x7fff90e4c9e0)
  Debug: Off
  Modified Time: 36963
  Reference Count: 1
  Registered Events: (none)
  Request: REQUEST_DATA
  FROM_OUTPUT_PORT: 0
  ALGORITHM_AFTER_FORWARD: 1
  FORWARD_DIRECTION: 0

I assume I must explicitly tell vtkGradientFilter which output arrays from TopoGridReader to use. How do I get the necessary information from TopoGridReader::GetOutput() and feed it to vtkGradientFilter? I know that my TopoGridReader connects without issue to vtkElevationFilter, without the need to send additional information to the filter:

gridReader->Update();
elevationFilter->SetInputConnection(gridReader->GetOutputPort();
elevationFilter->Update();

What’s different about vtkGradientFilter? I suspect I need to call vtkGradientFilter SetInputData(), SetInputScalars(), etc - but how do I get the necessary information from my TopoGridReader?
Thanks!

Apply vtkElevationFilter first, and then run vtkGradientFilter on the output of vtkElevationFilter.

1 Like

Thanks! When I do that the ‘no input error’ doesn’t occur - why does that work, and not computing gradient from the unfiltered source?

Moreover, gradientFilter output looks identical to the input (elevationFilter output)

The vtkElevationFilter adds an array to the vtkPointData. The vtkGradientFilter needs an array to operate on.

If you want, you can modify your reader so that it takes the Z coordinates and creates an array called “Elevation” and adds that array to the vtkPointData. But since vtkElevationFilter/vtkSimpleElevationFilter can already do that for you, there isn’t any real reason to do so.

1 Like

There’s no reason to “like” each and every one of my replies, for every “like” I get a notification from discourse, and it ends up being just too many notifications.

But TopoGridFilter outputs vtkCellArray and vtkPoints - those are not “arrays” that can be found by vtkGradientFilter?

And how do I get the vtkGradientFilter output connected to the mapper? I currently do the following:

 
mapper->SetInputConnection(gradientFilter_->GetOutputPort());

But the visualized data looks identical to the vtkElevationFilter output.
How do I examine the gradientFilter output? (Man, that sounds familiar, right? :wink: ) I do this:

 vtkPolyData *polyData = gradientFilter->GetPolyDataOutput();
  vtkCellArray *cells = polyData->GetPolys();
  vtkPoints *points = polyData->GetPoints();

But cells and points look identical to the filter input…
Thanks!

No, they’re not.

I’ll try to explain one more time: The point coordinates are stored in vtkPoints, and vtkPointData holds data values (in this case, elevation) associated with the points. It’s the latter that is operated upon by vtkGradientFilter (though of course it also needs the point coordinates, since it’s computing the gradient of some data value with respect to x,y,z).

Passing a dataset through vtkGradientFilter doesn’t change the geometry of the dataset, it only changes the arrays associated with the dataset (e.g. the arrays stored in vtkPointData). Perhaps after the data goes through vtkGradientFilter it has two arrays, one for the elevation and another for the gradient of the elevation, or maybe it has just the gradient, I’m not sure. But you can check this for yourself by getting the vtkPointData from the output and look through the arrays.

With the VTK mappers, it’s also possible to specify which array is used to color the data when it’s rendered.

Thank you again for all of your help!

gradientFilter->GetOutput()->GetPointData()->Print() gives

vtkPointData (0x7fedb4e40320)
  Debug: Off
  Modified Time: 40458
  Reference Count: 1
  Registered Events: 
    Registered Observers:
      vtkObserver (0x7fedb5a07b80)
        Event: 33
        EventName: ModifiedEvent
        Command: 0x7fedb4d80de0
        Priority: 0
        Tag: 1
  Number Of Arrays: 2
  Array 0 name = Elevation
  Array 1 name = Gradients
  Number Of Components: 4
  Number Of Tuples: 1613850
  Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 1 1 1 1 )
  Interpolate Flags: ( 1 1 1 1 1 0 0 1 1 1 1 0 )
  Pass Through Flags: ( 1 1 1 1 1 1 1 1 1 1 1 1 )
  Scalars: 
    Debug: Off
    Modified Time: 35280
    Reference Count: 2
    Registered Events: (none)
    Name: Elevation
    Data type: float
    Size: 1613850
    MaxId: 1613849
    NumberOfComponents: 1
    Information: 0
    Name: Elevation
    Number Of Components: 1
    Number Of Tuples: 1613850
    Size: 1613850
    MaxId: 1613849
    LookupTable: (none)
  Vectors: (none)
  Normals: (none)
  TCoords: (none)
  Tensors: (none)
  GlobalIds: (none)
  PedigreeIds: (none)
  EdgeFlag: (none)
  Tangents: (none)
  RationalWeights: (none)
  HigherOrderDegrees: (none)
  ProcessIds: (none)

So you’re right, two arrays, named “Elevation” and “Gradients”. Connecting to the mapper:

surfaceMapper->SetInputConnection(gradientFilter->GetOutputPort());
surfaceMapper->SetArrayName("Gradients");

(Note that vtkMapper::SetArrayName() returns void - so if I pass a bogus/misspelled array name it will silently fail.)

Yet the display still appears to be topography not gradient. I’m still missing something…

You might also need this, or else the mapper will ignore the ArrayName:

surfaceMapper->SetArrayAccessMode(VTK_GET_ARRAY_BY_NAME);

Unfortunately, I don’t know of any good documentation for vtkDataSetMapper and it really isn’t the easiest class to use…

Another issue is that you say you need to display the slope, but the gradient and the slope are not the same thing. The gradient has three components, which are the partial derivatives with respect to x, y, and z. My understanding is that the slope is the magnitude of the partial derivative of the elevation with respect to just x and y (not z). So between the gradient filter and the mapper, you would need a filter that can compute the slope from the gradient, basically by computing the magnitude of the first two components of the gradient. And I don’t know what filter that would be, because I don’t work with geological/topographical data. But there is probably someone on this discussion board that does know.

Good point about gradient vs slope @dgobbi - thanks