Source code for data_morph.shapes.bases.shape

"""Abstract base class for shapes."""

from __future__ import annotations

from abc import ABC, abstractmethod
from collections.abc import Iterable
from numbers import Number

import numpy as np
from matplotlib.axes import Axes


[docs] class Shape(ABC): """Abstract base class for a shape.""" name: str | None = None """The display name for the shape, if the lowercased class name is not desired."""
[docs] @classmethod def get_name(cls) -> str: """ Get the name of the shape. Returns ------- str The name of the shape. """ return cls.name or cls.__name__.lower()
def __repr__(self) -> str: """ Return string representation of the shape. Returns ------- str The unambiguous string representation of the shape. """ return self._recursive_repr() def __str__(self) -> str: """ Return string representation of the shape. Returns ------- str The human-readable string representation of the shape. See Also -------- get_name : This calls the :meth:`.get_name` class method. """ return self.get_name()
[docs] @abstractmethod def distance(self, x: Number, y: Number) -> float: """ Calculate the distance between this shape and a point (x, y). Parameters ---------- x, y : numbers.Number Coordinates of a point in 2D space. Returns ------- float The distance between this shape and the point (x, y). """ raise NotImplementedError
@staticmethod def _euclidean_distance(a: Iterable[Number], b: Iterable[Number]) -> float: """ Calculate the Euclidean distance between points a and b. Parameters ---------- a, b : Iterable[numbers.Number] Coordinates of points in two-dimensional space. Returns ------- float The Euclidean distance between a and b. See Also -------- numpy.linalg.norm : Euclidean distance calculation. """ return np.linalg.norm(a - b) def _recursive_repr(self, attr: str | None = None) -> str: """ Return string representation of the shape incorporating any items inside a specific attribute. Parameters ---------- attr : str, optional The attribute to incorporate into the result; must be iterable. Returns ------- str The unambiguous string representation of the shape. """ value = f'<{self.__class__.__name__}>' if not attr: return value indented_line = '\n ' offset = len(attr) + 4 hanging_indent = f'{indented_line:<{offset}}' return ( value + f'{indented_line}{attr}={hanging_indent}' + f'{hanging_indent}'.join(repr(item) for item in getattr(self, attr)) )
[docs] @abstractmethod def plot(self, ax: Axes | None = None) -> Axes: """ Plot the shape. Parameters ---------- ax : matplotlib.axes.Axes, optional An optional :class:`~matplotlib.axes.Axes` object to plot on. Returns ------- matplotlib.axes.Axes The :class:`~matplotlib.axes.Axes` object containing the plot. Notes ----- When implementing this method for subclasses, make sure to apply the :func:`.plotting.style.plot_with_custom_style` decorator. """ raise NotImplementedError