Skip to content




Demonstrate how to set up a callback with client data

Getting the camera orientation after interacting with the image is used as an example.

We define a callback passing the active camera as client data and linking the callback to the EndInteractionEvent of the vtkRenderWindowInteractor class. This allows us to get the camera orientation after we manipulate the image. We can then copy/paste this data as needed into our camera to set up a nice initial orientation as shown in the example.

To help orient the cone, we use a vtkOrientationMarkerWidget and a vtkOutlineFilter.


There are two methodologies in C++.

  1. Create a class that inherits from vtkCallbackCommand reimplementing Execute( vtkObject *caller, unsigned long evId, void*) and setting pointers to a client and/or call data as needed. When the class is implemented, it becomes the callback function.
  2. Create a function with this signature: void f( vtkObject * caller, long unsigned int evId, void* clientData, void* callData) and, where needed, create a vtkCallbackCommand setting its callback to the function we have created.

The example demonstrates both approaches.

In the function PrintCameraOrientation note how we convert an array to a vector and get a comma-separated list.


In Python the approach is even simpler. We simply define a function to use as the callback with this signature: def MyCallback(obj, ev):. Then, to pass client data to it, we simply do: MyCallback.myClientData = myClientData. This relies on the fact that Python functions are in fact objects and we are simply adding new attributes such as myClientData in this case.

An alternative method is to define a class passsing the needed variables in the __init__ function and then implement a _call__ function that does the work.

Both approaches are demonstrated in the example.

Other languages

See (Cxx), (Python)


If you have a question about this example, please use the VTK Discourse Forum


#!/usr/bin/env python3

Demonstrate the use of a callback.

We also add call data.

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersModeling import vtkOutlineFilter
from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
from vtkmodules.vtkRenderingCore import (

def get_program_parameters():
    import argparse
    description = 'Demonstrate two ways of using callbacks.'
    epilogue = '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
    parser.add_argument('-c', '--class_cb', action='store_false',
                        help='Use a class callback instead of a function  callback.')
    args = parser.parse_args()
    return args.class_cb

def main():
    #  Decide what approach to use.
    use_function_callback = get_program_parameters()

    colors = vtkNamedColors()

    # Create the Renderer, RenderWindow and RenderWindowInteractor.
    ren = vtkRenderer(background=colors.GetColor3d('MistyRose'))
    ren_win = vtkRenderWindow(size=(640, 640), window_name='CallBack')
    iren = vtkRenderWindowInteractor()
    iren.render_window = ren_win

    # Use a cone as a source with the golden ratio for the height. Because we can!
    source = vtkConeSource(center=(0, 0, 0), radius=1, height=1.6180339887498948482, resolution=128)

    # Pipeline
    mapper = vtkPolyDataMapper()
    source >> mapper
    actor = vtkActor(mapper=mapper) = colors.GetColor3d('Peacock')
    # Lighting = 0.6 = 0.2 = 1.0 = 20.0

    # Get an outline of the data set for context.
    outline = vtkOutlineFilter()
    outline_mapper = vtkPolyDataMapper()
    source >> outline >> outline_mapper
    outline_actor = vtkActor(mapper=outline_mapper) = colors.GetColor3d('Black') = 2

    # Add the actors to the renderer.

    # Set up a nice camera position.
    camera = vtkCamera()
    camera.position = (4.6, -2.0, 3.8)
    camera.focal_point = (0.0, 0.0, 0.0)
    camera.clipping_range = (3.2, 10.2)
    camera.view_up = (0.3, 1.0, 0.13)
    ren.active_camera = camera


    rgb = [0.0] * 4
    colors.GetColor("Carrot", rgb)
    rgb = tuple(rgb[:3])
    widget = vtkOrientationMarkerWidget(orientation_marker=make_axes_actor(),
                                        interactor=iren, default_renderer=ren,
                                        outline_color=rgb, viewport=(0.0, 0.0, 0.2, 0.2), zoom=1.5, enabled=True,

    # Set up the callback.
    if use_function_callback:
        # We are going to output the camera position when the event
        #   is triggered, so we add the active camera as an attribute. = ren.active_camera
        # Register the callback with the object that is observing.
        iren.AddObserver('EndInteractionEvent', get_orientation)
        iren.AddObserver('EndInteractionEvent', OrientationObserver(ren.active_camera))
        # Or:
        # observer = OrientationObserver(ren.active_camera)
        # iren.AddObserver('EndInteractionEvent', observer)


def get_orientation(caller, ev):
    Print out the orientation.

    We must do this before we register the callback in the calling function. = ren.active_camera

    :param caller: The caller.
    :param ev: The event.
    # Just do this to demonstrate who called callback and the event that triggered it.
    print(caller.class_name, 'Event Id:', ev)
    # Now print the camera orientation.

class OrientationObserver:
    def __init__(self, cam): = cam

    def __call__(self, caller, ev):
        # Just do this to demonstrate who called callback and the event that triggered it.
        print(caller.class_name, 'Event Id:', ev)
        # Now print the camera orientation.

def camera_orientation(cam):
    flt_fmt = '9.6g'
    fmt = '{:' + flt_fmt + '}'
    print(f'{"Position:":>15s},{" ".join(map(fmt.format, cam.position))}')
    print(f'{"Focal point:":>15s},{" ".join(map(fmt.format, cam.focal_point))}')
    print(f'{"Clipping range:":>15s},{" ".join(map(fmt.format, cam.clipping_range))}')
    print(f'{"View up:":>15s},{" ".join(map(fmt.format, cam.view_up))}')

def make_axes_actor():
    axes = vtkAxesActor(shaft_type=vtkAxesActor.CYLINDER_SHAFT, tip_type=vtkAxesActor.CONE_TIP,
                        x_axis_label_text='X', y_axis_label_text='Y', z_axis_label_text='Z',
                        total_length=(1.0, 1.0, 1.0))
    axes.cylinder_radius = 1.25 * axes.cylinder_radius
    axes.cone_radius = 1.25 * axes.cone_radius
    axes.sphere_radius = 1.5 * axes.sphere_radius

    colors = vtkNamedColors()
    axes.x_axis_caption_actor2d.caption_text_property.color = colors.GetColor3d('FireBrick')
    axes.y_axis_caption_actor2d.caption_text_property.color = colors.GetColor3d('DarkGreen')
    axes.z_axis_caption_actor2d.caption_text_property.color = colors.GetColor3d('DarkBlue')

    return axes

if __name__ == '__main__':