Source code for data_morph.shapes.circles

"""Shapes that are circular in nature."""

from numbers import Number

import matplotlib.pyplot as plt
from matplotlib.axes import Axes

from ..data.dataset import Dataset
from ..plotting.style import plot_with_custom_style
from .bases.shape import Shape


[docs]class Circle(Shape): """ Class representing a hollow circle. .. plot:: :scale: 75 :caption: This shape is generated using the panda dataset. from data_morph.data.loader import DataLoader from data_morph.shapes.circles import Circle _ = Circle(DataLoader.load_dataset('panda')).plot() Parameters ---------- dataset : Dataset The starting dataset to morph into other shapes. r : numbers.Number, optional The radius of the circle. """ def __init__(self, dataset: Dataset, r: Number = None) -> None: self.cx: Number = dataset.df.x.mean() """numbers.Number: The x coordinate of the circle's center.""" self.cy: Number = dataset.df.y.mean() """numbers.Number: The y coordinate of the circle's center.""" self.r: Number = r or dataset.df.std().mean() * 1.5 """numbers.Number: The radius of the circle.""" def __repr__(self) -> str: return f'<{self.__class__.__name__} cx={self.cx} cy={self.cy} r={self.r}>'
[docs] def distance(self, x: Number, y: Number) -> float: """ Calculate the absolute distance between this circle's edge and a point (x, y). Parameters ---------- x, y : numbers.Number Coordinates of a point in 2D space. Returns ------- float The absolute distance between this circle's edge and the point (x, y). """ return abs(self._euclidean_distance((self.cx, self.cy), (x, y)) - self.r)
[docs] @plot_with_custom_style def plot(self, ax: Axes = 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. """ if not ax: fig, ax = plt.subplots(layout='constrained') fig.get_layout_engine().set(w_pad=0.2, h_pad=0.2) _ = ax.axis('equal') _ = ax.add_patch(plt.Circle((self.cx, self.cy), self.r, ec='k', fill=False)) _ = ax.autoscale() return ax
[docs]class Bullseye(Shape): """ Class representing a bullseye shape comprising two concentric circles. .. plot:: :scale: 75 :caption: This shape is generated using the panda dataset. from data_morph.data.loader import DataLoader from data_morph.shapes.circles import Bullseye _ = Bullseye(DataLoader.load_dataset('panda')).plot() Parameters ---------- dataset : Dataset The starting dataset to morph into other shapes. """ def __init__(self, dataset: Dataset) -> None: stdev = dataset.df.std().mean() self.circles: list[Circle] = [Circle(dataset, r) for r in [stdev, stdev * 2]] """list[Circle]: The inner and outer :class:`Circle` objects.""" def __repr__(self) -> str: return self._recursive_repr('circles')
[docs] def distance(self, x: Number, y: Number) -> float: """ Calculate the minimum absolute distance between this bullseye's inner and outer circles' edges and a point (x, y). Parameters ---------- x, y : numbers.Number Coordinates of a point in 2D space. Returns ------- float The minimum absolute distance between this bullseye's inner and outer circles' edges and the point (x, y). See Also -------- Circle.distance : A bullseye consists of two circles, so we use the minimum distance to one of the circles. """ return min(circle.distance(x, y) for circle in self.circles)
[docs] @plot_with_custom_style def plot(self, ax: Axes = 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. """ for circle in self.circles: ax = circle.plot(ax) return ax