Shapes

Defines the shapes which are used with a ceed.function to create regions with time-varying intensity during an experiment ceed.stage.

PaintCanvasBehavior provides the widget functionality such that when a user draws on the screen, PaintShape instances are created and added to it.

CeedPaintCanvasBehavior provides a more specialized painter canvas. Specifically, in addition to being able to draw shapes, it adds the ability to organize shapes into CeedPaintCanvasBehavior.groups.

Shape plugin

Although Ceed does not offer a plugin for shapes, it’s simple to create shapes and shape groups with a script, dump it to disk as a yaml file, and import it into Ceed from the GUI.

Following is an example using CeedPaintCanvasBehavior and the methods of its baseclass PaintCanvasBehavior as well as using the Ceed-inherited versions of the shapes; CeedPaintCircle (PaintCircle), CeedPaintEllipse (PaintEllipse), CeedPaintPolygon (PaintPolygon).

Each shape class has a class method create_shape that can be used to create the shape, because you should not instantiate the shape class manually because the resulting shapes may not be valid:

from ceed.shape import CeedPaintCanvasBehavior, CeedPaintCircle,         CeedPaintEllipse, CeedPaintPolygon
from ceed.storage.controller import CeedDataWriterBase

# create shape factory to which we'll add shapes
shape_factory = CeedPaintCanvasBehavior()
# create the shapes and name them. We use the Shape classes from Ceed
ellipse = CeedPaintEllipse.create_shape(
    center=(250, 450), radius_x=200, radius_y=400, name='ellipse')
circle = CeedPaintCircle.create_shape(
    center=(700, 300), radius=200, name='circle')
polygon = CeedPaintPolygon.create_shape(
    points=[275, 300, 700, 300, 500, 800], name='polygon')

# add the shapes to factory
shape_factory.add_shape(ellipse)
shape_factory.add_shape(circle)
shape_factory.add_shape(polygon)

# create group, name it, and add shapes to it
group = shape_factory.add_group()
group.name = 'shapes'
group.add_shape(ellipse)
group.add_shape(polygon)

# save it to disk for import later
CeedDataWriterBase.save_config_to_yaml(
    filename, shape_factory=shape_factory)

You can also create the shapes by type name using create_shape():

from ceed.shape import CeedPaintCanvasBehavior
from ceed.storage.controller import CeedDataWriterBase

# create shape factory to which we'll add shapes
shape_factory = CeedPaintCanvasBehavior()

# create shape using config, including name
ellipse = shape_factory.create_shape(
    'ellipse', center=(250, 450), radius_x=200, radius_y=400,
    name='ellipse')
circle = shape_factory.create_shape(
    'circle', center=(700, 300), radius=200, name='circle')
polygon = shape_factory.create_shape(
    'polygon', points=[275, 300, 700, 300, 500, 800], name='polygon')

# add the shapes to factory
shape_factory.add_shape(ellipse)
shape_factory.add_shape(circle)
shape_factory.add_shape(polygon)

# create group, name it, and add shapes to it
group = shape_factory.add_group()
group.name = 'shapes'
group.add_shape(ellipse)
group.add_shape(polygon)

# save it to disk for import later
CeedDataWriterBase.save_config_to_yaml(
    filename, shape_factory=shape_factory)

See save_config_to_yaml() for a full example with functions/stages.

If you need to create many shapes or groups and importing them in the Ceed GUI is slow, consider setting its no_display or no_display to True. E.g. CeedPaintEllipse.create_shape(..., no_display=True).

The ProPixx projector used by Ceed has a resolution of 1920x108, so that should be the maximum extent of the shapes. The exact available drawing area can also be read/set in the config at screen_width and screen_height.

class ceed.shape.CeedPaintCanvasBehavior(**kwargs)

Bases: kivy_garden.painter.PaintCanvasBehavior

Controller base class for drawing and managing the shapes.

A shape is drawn by the user in the GUI and automatically added by kivy_garden.painter.PaintCanvasBehavior to its kivy_garden.painter.PaintCanvasBehavior.shapes list. This class manages all that without any of the associated GUI components that is shown to the user (e.g. the ability name shapes etc.). The GUI components is added by the CeedPainter.

So when run from the GUI, an instance of ceed.shape.shape_widgets.CeedPainter is the class used to manage the shapes. When running during analysis, and instance of this class is used instead as no visualizations is required..

In addition to the kivy_garden.painter.PaintCanvasBehavior.shapes, the class adds groups for grouping shapes; a CeedShapeGroup simply groups a collection of CeedShape by their name.

Events
on_remove_shape:

Triggered when a CeedShape is removed. The first parameter is the shape removed.

on_remove_group:

Triggered when a CeedShapeGroup is removed. The first parameter is the group removed.

on_changed:

Triggered whenever a CeedShape or CeedShapeGroup is added or removed, or if a configuration option of the objects is changed.

groups: List[ceed.shape.CeedShapeGroup]

List of CeedShapeGroup instances created in Ceed.

shape_names: Dict[str, ceed.shape.CeedShape]

The name -> CeedShape dict. The key is the shape’s name and the corresponding value is the CeedShape instance.

shape_group_names: Dict[str, ceed.shape.CeedShapeGroup]

The name -> CeedShapeGroup dict. The key is the group’s name and the corresponding value is the CeedShapeGroup instance.

unique_names: ceed.utils.UniqueNames = None

A set that tracks existing shape/group names to help us ensure all shapes/groups have unique names.

add_shape(shape: ceed.shape.CeedShape)

Add the shape to shapes and to the painter.

Parameters

shapePaintShape instance to add.

Returns

A bool indicating whether the shape was successfully added.

remove_shape(shape: ceed.shape.CeedShape)

Removes the shape from the painter and from shapes.

Parameters

shapePaintShape instance to remove.

Returns

A bool indicating whether the shape was successfully removed.

reorder_shape(shape: ceed.shape.CeedShape, before_shape: Optional[ceed.shape.CeedShape] = None)

Move the shape up or down in depth, in terms of the shape order in shapes and in the canvas.

This effect whether a shape will obscure another.

Parameters
  • shapePaintShape instance to move from it’s current position.

  • before_shape – Where to add it. If None, it is moved at the end, otherwise it is moved after the given PaintShape in shapes.

move_shape_lower(shape: ceed.shape.CeedShape)

Moves the shape one shape down. I.e. if there are two shapes and this shape is at index 1, it gets moved to index 0.

This changes the depth ordering of the shapes.

Parameters

shape – The CeedShape instance to move. It must exist in shapes.

move_shape_upwards(shape: ceed.shape.CeedShape)

Moves the shape one shape up. I.e. if there are two shapes and this shape is at index 0, it gets moved to index 1.

This changes the depth ordering of the shapes.

Parameters

shape – The CeedShape instance to move. It must exist in shapes.

add_group(group: Optional[ceed.shape.CeedShapeGroup] = None)

Similar to add_shape() but for a CeedShapeGroup.

Params
group: CeedShapeGroup

The group to add. If None, the default, a new CeedShapeGroup is created and added.

Returns

The CeedShapeGroup added.

remove_group(group: ceed.shape.CeedShapeGroup)

Similar to remove_shape() but for a CeedShapeGroup.

Params
group: CeedShapeGroup

The group to remove.

Returns

True if the group was removed, False otherwise.

remove_all_groups()

Removes all the CeedShapeGroup instances in groups.

add_selected_shapes_to_group(group: Optional[ceed.shape.CeedShapeGroup] = None)

Adds all the kivy_garden.painter.PaintCanvasBehavior.selected_shapes to the group.

Params
group: CeedShapeGroup

The group to which to add the shapes. If None, the default, a new CeedShapeGroup is created.

Returns

The CeedShapeGroup passed in or created.

remove_shape_from_groups(shape: ceed.shape.CeedShape)

Removes the CeedShape from all the groups.

Params
shape: CeedShape

The shape to remove.

get_state(use_cache=False) dict

Returns a dictionary containing all the configuration data for all the shapes and groups. It is used with set_state() to later restore the state.

Parameters

use_cache – If True, it’ll get the state using the cache from previous times the state was read and cached, if the cache exists.

create_shape_from_state(state: dict, old_name_map: Dict[str, ceed.shape.CeedShape])

Overrides kivy_garden.painter.PaintCanvasBehavior.create_shape_from_state() and changes its signature.

It takes an additional parameter, old_name_map. When a shape is created from the given state, the shape’s new name could have been changed automatically so that it remained unique. old_name_map is a dict that is filled in so the key is the old name (if present in state) and the associated value is the actual final shape name.

set_state(state: dict, old_name_map: Dict[str, Union[ceed.shape.CeedShape, ceed.shape.CeedShapeGroup]])

Takes the dict returned by get_state() and adds the shapes and groups created form them.

old_name_map is the same as in create_shape_from_state().

class ceed.shape.CeedShape(paint_widget_size=(0, 0), **kwargs)

Bases: object

A co-base class used with kivy_garden.painter.PaintShape derived classes to add Ceed specific functionality to the kivy_garden.painter.PaintShape classes.

name: str

A unique name associated with the shape.

no_display: bool

If set to True, the shape will not be displayed in the GUI, but it will still work like normal shapes during an experiment if it’s in a stage.

Not displaying the shape can make the stage/function/shape config load faster when importing from e.g. a yaml file because we don’t have to display it in the GUI. However, the shapes won’t be able to be added to a stage through the GUI, so you’d need to add it to the stage in the same script that generates the shapes. Or, add them to groups and leave the groups visible so it can be dragged to the stage.

widget = None

The WidgetShape used by ceed to customize the shape in the GUI.

paint_widget_size = (0, 0)

The size of the area used to draw the shapes. A shape is not allowed to have coordinates outside this area.

get_cached_state(use_cache=False) Dict

Like get_state(), but it caches the result. And next time it is called, if use_cache is True, the cached value will be returned, unless the config changed in between. Helpful for backup so we don’t recompute the full state.

Parameters

use_cache – If True, it’ll get the state using the cache from previous times the state was read and cached, if the cache exists.

Returns

The state dict.

get_state() dict

Returns a dict representing the shape.

property bounding_box

Returns the (x1, y1, x2, y2) describing the lower left and upper right points that define a bounding box for the shape.

property centroid

Returns the estimated (x, y) centroid of the shape.

property area

Returns the estimated area of the shape.

set_area(area)

Sets the internal area of the shape in pixels. We try to get close to the requested area, but it is not likely to be exact.

Parameters

area – The area to be set.

property collider

Returns the collider instance from kivy_garden.collider used to manipulate and measure the shapes.

class ceed.shape.CeedShapeGroup(**kwargs)

Bases: kivy._event.EventDispatcher

Holds a collection of CeedShape instances.

It is helpful to group them when the same ceed.function is to be applied to multiple shapes.

Events
on_changed:

Triggered whenever a child CeedShape is added or removed, or if a configuration option of the objects is changed.

paint_widget

The same as kivy_garden.painter.PaintShape.paint_widget.

name: str

The unique name of the group. Similar to CeedShape.name.

no_display: bool

Same as CeedShape.no_display, but for this group.

shapes: List[ceed.shape.CeedShape]

A list that contains the CeedShape instances that are part of this group.

widget = None

The WidgetShapeGroup used by ceed to customize the group in the GUI.

get_cached_state(use_cache=False) Dict

Like get_state(), but it caches the result. And next time it is called, if use_cache is True, the cached value will be returned, unless the config changed in between. Helpful for backup so we don’t recompute the full state.

Parameters
  • use_cache – If True, it’ll get the state using the cache from previous times the state was read and cached, if the cache exists.

  • use_cache – If True, it’ll get the state using the cache from previous times the state was read and cached, if the cache exists.

Returns

The state dict.

get_state() dict

Returns a dict representing the shape group.

add_shape(shape: ceed.shape.CeedShape)

Adds the shape to the group if it is not already in the group.

Params
shape: CeedShape

The shape to add to shapes.

Returns

Whether the shape was successfully added to the group.

remove_shape(shape: ceed.shape.CeedShape)

Removes the shape from the group (and its CeedShape.widget) if it is present.

Params
shape: CeedShape

The shape to remove from shapes.

remove_all()

Removes all the shapes from the group.

class ceed.shape.CeedPaintCircle(paint_widget_size=(0, 0), **kwargs)

Bases: ceed.shape.CeedShape, kivy_garden.painter.PaintCircle

A circle shape.

class ceed.shape.CeedPaintEllipse(paint_widget_size=(0, 0), **kwargs)

Bases: ceed.shape.CeedShape, kivy_garden.painter.PaintEllipse

An ellipse shape.

class ceed.shape.CeedPaintPolygon(paint_widget_size=(0, 0), **kwargs)

Bases: ceed.shape.CeedShape, kivy_garden.painter.PaintPolygon

A polygonal shape.

class ceed.shape.CeedPaintFreeformPolygon(paint_widget_size=(0, 0), **kwargs)

Bases: ceed.shape.CeedShape, kivy_garden.painter.PaintFreeformPolygon

A polygonal shape drawn using freeform points.