# Modifying a filter's output array?

**URL:** https://discourse.vtk.org/t/modifying-a-filters-output-array/1820
**Category:** Support
**Created:** [September 25, 2019, 2:16pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820 "2019-09-25T14:16:25Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![TravStu22](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/t/439d5e/32.png) [@TravStu22](https://discourse.vtk.org/u/TravStu22)
#### Post date: [September 25, 2019, 2:16pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/1 "2019-09-25T14:16:25Z")

</div>

Hi. I like the scaling behavior I get when using the vtk.vtkDistanceToCamera() filter on my point cloud that’s zoomed out. It keeps my points visible. But I’d like it to quit this scaling when I zoom in. Basically I think I want the array values produced by this filter to not drop below 1.

Is there an existing filter I can use to do this? If not, I think I need to manually modify the array. But how do I access this array?

Thanks, and here is some demo python code where I’m using vtkDistanceToCamera.

```
import vtk

renderer = vtk.vtkRenderer()

points_b = vtk.vtkPoints()

for x in range(0, 3):
    for y in range(0, 4):
        for z in range(0, 3):
            points_b.InsertNextPoint(x*40 + 6, y*40, z*40)

poly_data_b = vtk.vtkPolyData()
poly_data_b.SetPoints(points_b)

sphere = vtk.vtkSphereSource()
sphere.SetPhiResolution(24)
sphere.SetThetaResolution(24)
sphere.SetRadius(3)

camera_dist_b = vtk.vtkDistanceToCamera()
camera_dist_b.SetInputData(poly_data_b)
camera_dist_b.SetRenderer(renderer)
camera_dist_b.SetScreenSize(3)

#a filter here to cap camera_dist_b's output to greater than one?

mapper_b = vtk.vtkGlyph3DMapper()
mapper_b.SetInputData(poly_data_b)
mapper_b.SetSourceConnection(sphere.GetOutputPort())
mapper_b.SetInputConnection(camera_dist_b.GetOutputPort())
mapper_b.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS, 'DistanceToCamera')

actor_b = vtk.vtkActor()
actor_b.SetMapper(mapper_b)
actor_b.GetProperty().SetColor(0, 1, 0)
renderer.AddActor(actor_b)

render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
style = vtk.vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
interactor.SetRenderWindow(render_window)
renderer.SetBackground(1, 1, 1)
renderer.ResetCamera()
renderer.GetActiveCamera().Zoom(8)
render_window.Render()
interactor.Start()
```

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [September 25, 2019, 11:25pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/2 "2019-09-25T23:25:50Z")

</div>

You could first try thresholding the scaling factors manually using numpy. If you get the desired effect, then you may consider adding this feature to vtkDistanceToCamera class (probably it can be implemented in 10-20 lines) and submit a merge request to the official VTK repository.

In 3D Slicer markups we use a slightly different approach: We don’t use distance filter, this way points that are closer to the camera always appear somewhat larger (this is an important 3D hint). To prevent markups to become invisible or become so large that they occlude everything else, we set constant scaling based on scaling factor at the camera focal point. We also give users the option to switch between true physical size and this normalized scale. See implementation here: [https://github.com/Slicer/Slicer/blob/master/Modules/Loadable/Markups/VTKWidgets/vtkSlicerMarkupsWidgetRepresentation3D.cxx](https://github.com/Slicer/Slicer/blob/master/Modules/Loadable/Markups/VTKWidgets/vtkSlicerMarkupsWidgetRepresentation3D.cxx)

---

<div class="post-metadata">

### Author: ![TravStu22](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/t/439d5e/32.png) [@TravStu22](https://discourse.vtk.org/u/TravStu22)
#### Post date: [September 26, 2019, 12:44pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/3 "2019-09-26T12:44:18Z")

</div>

That’s an interesting approach with 3D Slicer.

> You could first try thresholding the scaling factors manually using numpy.

I would like to try this, but I don’t know how to get access to this array in order to manipulate it. If I understand, this manipulation would need to occur in a custom filter that sits between vtkDistanceToCamera and vtkGlyph3DMapper, since the output of d2c changes when the camera moves.

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [October 5, 2019, 2:37am UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/4 "2019-10-05T02:37:30Z")

</div>

No need to create a custom filter. You can just observe camera changes, perform the necessary updates, and request a render (this is how it works in Slicer, too).

You can get read/write access to VTK arrays as numpy arrays using [`vtk.util.numpy_support`](https://github.com/Kitware/VTK/blob/master/Wrapping/Python/vtkmodules/util/numpy_support.py). See example usage [here](https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/util.py#L1002-L1012).

---

<div class="post-metadata">

### Author: ![TravStu22](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/t/439d5e/32.png) [@TravStu22](https://discourse.vtk.org/u/TravStu22)
#### Post date: [October 5, 2019, 3:38pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/5 "2019-10-05T15:38:40Z")

</div>

I’ve made some progress, thanks.  
I can now access and modify the DistanceToCamera array when the interactor is modified.  
However, it has no effect on the rendering. And if I read out the array after the renderer is closed, I see it contains unclipped values.

I suspect that this array is getting overwritten with its normal values AFTER I modify it and _then_ the render is using it. Any ideas how I can change this order of operations?

Here is the code so far with the camera callback up top.

```
import vtk
import vtk.util.numpy_support
import numpy

def clip_distance_array(self, event):
    print(event)

    vtk_array = camera_dist_b.GetOutputDataObject(0).GetPointData().GetArray('DistanceToCamera')
    numpy_array = vtk.util.numpy_support.vtk_to_numpy(vtk_array)

    numpy.clip(numpy_array, 1, 100, out=numpy_array)

    vtk_array.DataChanged()
    vtk_array.Modified()
    
    camera_dist_b.Modified()
    mapper_b.Modified()
    
    camera_dist_b.Update()
    mapper_b.Update()

    render_window.Render()

    print(numpy_array)
    print(vtk_array.GetValueRange())

renderer = vtk.vtkRenderer()

points_b = vtk.vtkPoints()

for x in range(0, 3):
    for y in range(0, 4):
        for z in range(0, 3):
            points_b.InsertNextPoint(x*40 + 6, y*40, z*40)

poly_data_b = vtk.vtkPolyData()
poly_data_b.SetPoints(points_b)

sphere = vtk.vtkSphereSource()
sphere.SetPhiResolution(24)
sphere.SetThetaResolution(24)
sphere.SetRadius(3)

camera_dist_b = vtk.vtkDistanceToCamera()
camera_dist_b.SetInputData(poly_data_b)
camera_dist_b.SetRenderer(renderer)
camera_dist_b.SetScreenSize(3)

mapper_b = vtk.vtkGlyph3DMapper()
mapper_b.SetInputData(poly_data_b)
mapper_b.SetSourceConnection(sphere.GetOutputPort())
mapper_b.SetInputConnection(camera_dist_b.GetOutputPort())
mapper_b.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS, 'DistanceToCamera')

actor_b = vtk.vtkActor()
actor_b.SetMapper(mapper_b)
actor_b.GetProperty().SetColor(0, 1, 0)
renderer.AddActor(actor_b)

render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
style = vtk.vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
interactor.SetRenderWindow(render_window)
renderer.SetBackground(1, 1, 1)
renderer.ResetCamera()
renderer.GetActiveCamera().Zoom(8)

interactor.AddObserver("ModifiedEvent", clip_distance_array)

render_window.Render()
interactor.Start()

print(' ________________________________')
print('Final look at the array:')

vtk_array = camera_dist_b.GetOutputDataObject(0).GetPointData().GetArray('DistanceToCamera')

print(vtk_array.GetValueRange())
for index in range(vtk_array.GetNumberOfValues()):
    print(vtk_array.GetValue(index))
```

---

<div class="post-metadata">

### Author: ![TravStu22](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/t/439d5e/32.png) [@TravStu22](https://discourse.vtk.org/u/TravStu22)
#### Post date: [April 3, 2023, 10:46pm UTC](https://discourse.vtk.org/t/modifying-a-filters-output-array/1820/6 "2023-04-03T22:46:55Z")

</div>

I’m very close to achieving my goal. Only now my rendering is flashing between my desired clipped scaling and the normal scaling that vtkDistanceToCamera provides while I interact with the vtkRenderWindowInteractor. When I let go of the mouse, the desired clipped scaling is shown.

I made this progress by changing the clipping code to be tied to the RenderEvent instead of the ModifiedEvent and removing the Update/Modified calls on the vtkDistanceToCamera and vtkGlyph3DMapper objects in my clipping code.

I think to finish this off I just need to ensure my clipping code gets executed **every time** before a rendering happens… but how if RenderEvent doesn’t cut it? Tieing it to InteractionEvent doesn’t help either.

Here’s the current status code:

```auto
import vtk
import vtk.util.numpy_support
import numpy

def clip_distance_array(self, event):
    print(event)

    vtk_array = camera_dist_b.GetOutputDataObject(0).GetPointData().GetArray('DistanceToCamera')
    numpy_array = vtk.util.numpy_support.vtk_to_numpy(vtk_array)

    numpy.clip(numpy_array, 1, 100, out=numpy_array)

    vtk_array.DataChanged()
    vtk_array.Modified()
    
    print(numpy_array)
    print(vtk_array.GetValueRange())

renderer = vtk.vtkRenderer()

points_b = vtk.vtkPoints()

for x in range(0, 3):
    for y in range(0, 4):
        for z in range(0, 3):
            points_b.InsertNextPoint(x*40 + 6, y*40, z*40)

poly_data_b = vtk.vtkPolyData()
poly_data_b.SetPoints(points_b)

sphere = vtk.vtkSphereSource()
sphere.SetPhiResolution(24)
sphere.SetThetaResolution(24)
sphere.SetRadius(3)

camera_dist_b = vtk.vtkDistanceToCamera()
camera_dist_b.SetInputData(poly_data_b)
camera_dist_b.SetRenderer(renderer)
camera_dist_b.SetScreenSize(3)

mapper_b = vtk.vtkGlyph3DMapper()
mapper_b.SetInputData(poly_data_b)
mapper_b.SetSourceConnection(sphere.GetOutputPort())
mapper_b.SetInputConnection(camera_dist_b.GetOutputPort())
mapper_b.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS, 'DistanceToCamera')

actor_b = vtk.vtkActor()
actor_b.SetMapper(mapper_b)
actor_b.GetProperty().SetColor(0, 1, 0)
renderer.AddActor(actor_b)

render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
style = vtk.vtkInteractorStyleTrackballCamera()
interactor.SetInteractorStyle(style)
interactor.SetRenderWindow(render_window)
renderer.SetBackground(1, 1, 1)
renderer.ResetCamera()
renderer.GetActiveCamera().Zoom(8)

#interactor.AddObserver("ModifiedEvent", clip_distance_array)
interactor.AddObserver("RenderEvent", clip_distance_array)
#interactor.AddObserver("InteractionEvent", clip_distance_array)

render_window.Render()
interactor.Start()

print(' ________________________________')
print('Final look at the array:')

vtk_array = camera_dist_b.GetOutputDataObject(0).GetPointData().GetArray('DistanceToCamera')

print(vtk_array.GetValueRange())
for index in range(vtk_array.GetNumberOfValues()):
    print(vtk_array.GetValue(index))

```
