Source code for movement.roi.polygon
"""2-dimensional regions of interest."""
from __future__ import annotations
from collections.abc import Sequence
from movement.roi.base import BaseRegionOfInterest, PointLikeList
from movement.roi.line import LineOfInterest
[docs]
class PolygonOfInterest(BaseRegionOfInterest):
"""Representation of a two-dimensional region in the x-y plane.
This class can be used to represent polygonal regions or subregions
of the area in which the experimental data was gathered. These might
include the arms of a maze, a nesting area, a food source, or other
similar areas of the experimental enclosure that have some significance.
An instance of this class can be used to represent these regions of
interest (RoIs) in an analysis. The basic usage is to construct an
instance of this class by passing in a list of points, which will then be
joined (in sequence) by straight lines between consecutive pairs of points,
to form the exterior boundary of the RoI. Note that the exterior boundary
(accessible as via the ``.exterior`` property) is a (closed)
``LineOfInterest``, and may be treated accordingly.
The class also supports holes - subregions properly contained inside the
region that are not part of the region itself. These can be specified by
the ``holes`` argument, and define the interior boundaries of the region.
These interior boundaries are accessible via the ``.interior_boundaries``
property, and the polygonal regions that make up the holes are accessible
via the ``holes`` property.
"""
def __init__(
self,
exterior_boundary: PointLikeList,
holes: Sequence[PointLikeList] | None = None,
name: str | None = None,
) -> None:
"""Create a new region of interest (RoI).
Parameters
----------
exterior_boundary : tuple of (x, y) pairs
The points (in sequence) that make up the boundary of the region.
At least three points must be provided.
holes : sequence of sequences of (x, y) pairs, default None
A sequence of items, where each item will be interpreted as the
``exterior_boundary`` of an internal hole within the region. See
the ``holes`` argument to ``shapely.Polygon`` for details.
name : str, optional
Name of the RoI that is to be created. A default name will be
inherited from the base class if not provided.
See Also
--------
movement.roi.base.BaseRegionOfInterest : The base class that
constructor arguments are passed to, and defaults are inherited
from.
"""
super().__init__(
points=exterior_boundary, dimensions=2, holes=holes, name=name
)
@property
def exterior_boundary(self) -> LineOfInterest:
"""The exterior boundary of this RoI."""
return LineOfInterest(
self.region.exterior.coords,
loop=True,
name=f"Exterior boundary of {self.name}",
)
@property
def holes(self) -> tuple[PolygonOfInterest, ...]:
"""The interior holes of this RoI.
Holes are regions properly contained within the exterior boundary of
the RoI that are not part of the RoI itself (like the centre of a
doughnut, for example). A region with no holes returns the empty tuple.
"""
return tuple(
PolygonOfInterest(
int_boundary.coords, name=f"Hole {i} of {self.name}"
)
for i, int_boundary in enumerate(self.region.interiors)
)
@property
def interior_boundaries(self) -> tuple[LineOfInterest, ...]:
"""The interior boundaries of this RoI.
Interior boundaries are the boundaries of holes contained within the
polygon. A region with no holes returns the empty tuple.
"""
return tuple(
LineOfInterest(
int_boundary.coords,
loop=True,
name=f"Interior boundary {i} of {self.name}",
)
for i, int_boundary in enumerate(self.region.interiors)
)