Source code for data_morph.shapes.points.spade

"""Spade shape."""

from numbers import Number

import numpy as np

from ...data.dataset import Dataset
from ..bases.point_collection import PointCollection
from .heart import Heart


[docs] class Spade(PointCollection): """ Class for the spade shape. .. plot:: :scale: 75 :caption: This shape is generated using the panda dataset. from data_morph.data.loader import DataLoader from data_morph.shapes.points import Spade _ = Spade(DataLoader.load_dataset('panda')).plot() Parameters ---------- dataset : Dataset The starting dataset to morph into other shapes. """ def __init__(self, dataset: Dataset) -> None: x_bounds = dataset.data_bounds.x_bounds y_bounds = dataset.data_bounds.y_bounds x_shift = sum(x_bounds) / 2 y_shift = sum(y_bounds) / 2 # upside-down heart heart_points = self._get_inverted_heart(dataset, y_shift) # base of the spade base_x, base_y = self._get_base(x_bounds[1], x_shift, y_shift) # combine all points x = np.concatenate((heart_points[:, 0], base_x), axis=0) y = np.concatenate((heart_points[:, 1], base_y), axis=0) super().__init__(*np.stack([x, y], axis=1)) @staticmethod def _get_inverted_heart(dataset: Dataset, y_shift: Number) -> np.ndarray: """ Get points for an inverted heart. Parameters ---------- dataset : Dataset The starting dataset to morph into other shapes. y_shift : Number The constant value to shift the *y* up/down by. Returns ------- numpy.ndarray The points for the upside-down heart. See Also -------- Heart : This shape is reused to calculate the spade. """ heart_points = Heart(dataset).points heart_points[:, 1] = -heart_points[:, 1] + 2 * y_shift return heart_points @staticmethod def _get_base( xmax: Number, x_shift: Number, y_shift: Number ) -> tuple[np.ndarray, np.ndarray]: """ Get the base of the spade. Parameters ---------- xmax : Number The maximum *x* value for the shape. x_shift : Number The constant value to shift the *x* left/right by. y_shift : Number The constant value to shift the *y* up/down by. Returns ------- tuple[numpy.ndarray, numpy.ndarray] The *x* and *y* coordinates for the base of the spade. """ # line base line_x = np.linspace(-6, 6, num=12) line_y = np.repeat(-16, 12) # left wing left_x = np.linspace(-6, 0, num=12) left_y = 0.278 * np.power(left_x + 6, 2) - 16 # right wing right_x = np.linspace(0, 6, num=12) right_y = 0.278 * np.power(right_x - 6, 2) - 16 # shift and scale the base and wing base_x = np.concatenate((line_x, left_x, right_x), axis=0) base_y = np.concatenate((line_y, left_y, right_y), axis=0) # scale by the half the widest width of the spade scale_factor = (xmax - x_shift) / 16 base_x = base_x * scale_factor + x_shift base_y = base_y * scale_factor + y_shift return base_x, base_y