Ceed stages

A Ceed stage uses its functions to control the intensity of its shapes during an experiment.

A stage contains functions, shapes, and children stages. Each experiments runs a root stage and this stage ticks through its functions and children stages. For every video frame the current time is computed as the frame number multiplied by the period of the video frame rate. This time is passed to the functions and sub-stages which set their corresponding shapes for that frame from their functions’ return value.

See the stage API for in-depth stage details.

Creating stages

Ceed comes with a pre-defined stage with various parameters, but a plugin can create custom stage classes and add them to the available stages list. Additionally, you can customize stages in the stage pane to make it available for re-use in other stages or to be run directly.

This video shows multiple how to create a stage and name it, how to drag a sequence of functions into it and how to drag a shape and shape group into it.

Each stage has three “shelves” where you can drag objects ordered vertically as stages, functions, and shapes. The controller only lets you drop the dragged object into the correct shelf, depending on the object.

Previewing stage

Once we have a stage with functions and shapes, when run as an experiment Ceed will go through these functions sequentially until each is done before moving to the next. Meanwhile, for every frame, it applies the intensity from the current function for all its shapes.

You can preview the exact temporal sequence of intensity that each shape will experience.

Select the stage to preview, the sampling rate (it should match the projector rate for best accuracy, but it could take a while to pre-compute the entire stage) and refresh to compute.

You can select which color channel (red, green, blue) to preview and zoom to specific time intervals to see its intensity.

For example in this video, only the blue channel and only three shapes have intensity, the others have zero intensity (black). The temporal pattern is a cosine (“Slow”) for 30 seconds followed by a constant intensity for a few seconds (the duration and intensity is randomized by the function). Function’s output are clipped to the 0-1 range.

Modifying functions

Rather than modifying the functions in the function pane, you can modify the function directly in the stage. When originally adding the function, it uses a reference to the original function following any changes to it. Pressing the T-fork button will replace it with an editable function that is a copy of the referenced function.

We can also set the stage to loop over its function sequence, e.g. 3 times in the video.

Running preview stage

You can preview the frames of a stage by running it in the drawing area and it will play the exact sequence of intensity for each shape as during a real experiment.

Select the stage name from the dropdown and then press the play button to preview. Press stop to end it (or wait until it’s done).

Notice the “experiment sampled” named stage that is created when running. This stage is automatically created from the selected stage and is the stage that is run. It contains all concrete values generated by the randomized parameters. See also logged-experiment.

Ceed config of the video

Shape color

You can select the any of the three red, green, and blue color channels to be set by the function intensity value. The other channels are kept at zero.

Ceed config of the video

Sub-stages

To apply different temporal patterns to different shapes or shape groups, you can add these shapes to different stages, and then place the stages into a single root stage that runs them.

A stage applies its functions to its shapes. But, it can contain sub-stages that will simultaneously apply their functions to their shapes. A shape contained in multiple stages, the most deeply nested stage wins if both stages are active simultaneously.

In this video, we create two sub-stages directly in the stage, one sets two shapes to a cosine with frequency 2Hz, the other to sets its two shapes to a frequency of 1Hz. Additionally, one sets its shapes to cyan, the other to purple.

Initially, the two sub-stages will be run one after the other (serially) looping twice. Then we set their order to run in parallel.

Ceed config of the video

Donut stage shapes

The color of a shape’s internal area is uniformly set to its intensity value. To create a donut-style shape, where some internal part is black, you could draw the internal shape and create two sub-stages, each with their own function, one a cosine and one constant with zero intensity etc.

A simpler way is to mark “keep dark” in the internal shape’s stage settings. Then the shape will be kept dark at all times.

Ceed config of the video

Create stage in script

A stage complete with functions and shapes can be created in a script, saved to a yaml file, and then imported from the GUI ready to be used in an experiment. See the CeedDataWriterBase.save_config_to_yaml method for an example.

Stage plugin

Ceed comes with a blank stage baseclass, however using plugins Ceed can support any custom stage.

It is fully explained in Stage plugins, but you can make your plugin available to Ceed by copying your Python file to the ceed/stage/plugin directory under where Ceed is installed, or register your external plugin package using external_stage_plugin_package.

Ceed gets your stage classes using a get_ceed_stages function in the plugin.

To write a plugin, it helps to become familiar with the stage API and the CeedStage class that all stages inherit from.

A very simple stage plugin file that sets the intensity of all its shapes to t ^ 2, where t is the elapsed time is, and it lasts for 1 second for each loop iteration:

from ceed.stage import CeedStage, StageDoneException


class GrowStage(CeedStage):

    def __init__(self, **kwargs):
        self.name = 'Grow'
        super().__init__(**kwargs)

    def evaluate_stage(self, shapes, last_end_t):
        r = self.color_r
        g = self.color_g
        b = self.color_b

        # always get the first time
        self.t_start = t = yield
        for _ in range(self.loop):
            t_start = t

            # only go for 1 second
            while t - t_start < 1:
                intensity = (t - t_start) ** 2

                # set the r, g, b for those color channels used. Alpha is None
                for name, shape_values in shapes.items():
                    shape_values.append((
                        intensity if r else 0.,
                        intensity if g else 0.,
                        intensity if b else 0.,
                        None
                    ))
                # this yields so GUI can draw shapes and resume for next frame
                t = yield

        # this time value was not used so it ends on the last sample so
        # that last time will be used as start of next stage and MUST be saved
        # as t_end
        self.t_end = t
        # this is how we indicate we're done
        raise StageDoneException


def get_ceed_stages(stage_factory):
    return [GrowStage]

Simply copy the above code into your python file and place it in your external package or in Ceed’s plugin directory, e.g. ceed/stage/plugin/my_plugin.py and Grow will be listed in the GUI. Make an instance of it and drag shapes into it and it can used to run an experiment without needing to add any functions (but you could if you wanted to use them somehow).

Custom graphics

Besides the shapes drawn in the Ceed GUI or script generated, stages could add arbitrary Kivy GL graphics to the experiment screen and update them during an experiment. This e.g. allows the display of a circle whose intensity falls off as it’s farther from the center of the circle.

See the example plugins in the examples directory or the example code section in the docs.