diff --git a/docs/tutorials/shape-creation.rst b/docs/tutorials/shape-creation.rst index 2cd1d19d..5bf7a66f 100644 --- a/docs/tutorials/shape-creation.rst +++ b/docs/tutorials/shape-creation.rst @@ -64,8 +64,7 @@ to calculate its position and scale: name = 'x' def __init__(self, dataset: Dataset) -> None: - xmin, xmax = dataset.morph_bounds.x_bounds - ymin, ymax = dataset.morph_bounds.y_bounds + (xmin, xmax), (ymin, ymax) = dataset.morph_bounds super().__init__([[xmin, ymin], [xmax, ymax]], [[xmin, ymax], [xmax, ymin]]) diff --git a/src/data_morph/bounds/bounding_box.py b/src/data_morph/bounds/bounding_box.py index e137aa73..1fe77437 100644 --- a/src/data_morph/bounds/bounding_box.py +++ b/src/data_morph/bounds/bounding_box.py @@ -61,6 +61,19 @@ def __init__( ) """Interval: The bounds for the y direction.""" + self._bounds = (self.x_bounds, self.y_bounds) + + def __iter__(self) -> Interval: + """ + Iterate over the bounds in the bounding box. + + Returns + ------- + Interval + The next set of bounds. + """ + return iter(self._bounds) + def __contains__(self, value: Iterable[Number]) -> bool: """ Add support for using the ``in`` operator to check whether @@ -95,7 +108,7 @@ def __eq__(self, other: BoundingBox) -> bool: """ if not isinstance(other, BoundingBox): raise TypeError('Equality is only defined between BoundingBox objects.') - return self.x_bounds == other.x_bounds and self.y_bounds == other.y_bounds + return self._bounds == other._bounds def __repr__(self) -> str: return f'\n x={self.x_bounds}\n y={self.y_bounds}' diff --git a/src/data_morph/data/dataset.py b/src/data_morph/data/dataset.py index 3b2b2e6e..215c3fa6 100644 --- a/src/data_morph/data/dataset.py +++ b/src/data_morph/data/dataset.py @@ -220,8 +220,9 @@ def plot( scale_base = 85 # data bounds - x_offset = self.data_bounds.x_bounds.range / scale_base - y_offset = self.data_bounds.y_bounds.range / scale_base + x_range, y_range = self.data_bounds.range + x_offset = x_range / scale_base + y_offset = y_range / scale_base data_rectangle = [ self.data_bounds.x_bounds[0] - x_offset, self.data_bounds.y_bounds[0] - y_offset, @@ -230,8 +231,8 @@ def plot( ax.add_patch( plt.Rectangle( data_rectangle, - width=self.data_bounds.x_bounds.range + x_offset * 2, - height=self.data_bounds.y_bounds.range + y_offset * 2, + width=x_range + x_offset * 2, + height=y_range + y_offset * 2, ec='blue', linewidth=2, fill=False, @@ -239,7 +240,7 @@ def plot( ) ax.text( (self.data.x.max() + self.data.x.min()) / 2, - self.data.y.max() + self.data_bounds.y_bounds.range / scale_base, + self.data.y.max() + y_offset, 'DATA BOUNDS', color='blue', va='bottom', diff --git a/src/data_morph/shapes/lines/high_lines.py b/src/data_morph/shapes/lines/high_lines.py index 20c4354c..06ca74a4 100644 --- a/src/data_morph/shapes/lines/high_lines.py +++ b/src/data_morph/shapes/lines/high_lines.py @@ -27,8 +27,7 @@ class HighLines(LineCollection): name = 'high_lines' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds - y_bounds = dataset.data_bounds.y_bounds + x_bounds, y_bounds = dataset.data_bounds offset = y_bounds.range / 5 lower = y_bounds[0] + offset diff --git a/src/data_morph/shapes/lines/horizontal_lines.py b/src/data_morph/shapes/lines/horizontal_lines.py index 37ea3fb2..80be7772 100644 --- a/src/data_morph/shapes/lines/horizontal_lines.py +++ b/src/data_morph/shapes/lines/horizontal_lines.py @@ -29,8 +29,7 @@ class HorizontalLines(LineCollection): name = 'h_lines' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds - y_bounds = dataset.data_bounds.y_bounds + x_bounds, y_bounds = dataset.data_bounds super().__init__( *[ diff --git a/src/data_morph/shapes/lines/slant_down.py b/src/data_morph/shapes/lines/slant_down.py index 7392275e..931779a9 100644 --- a/src/data_morph/shapes/lines/slant_down.py +++ b/src/data_morph/shapes/lines/slant_down.py @@ -27,8 +27,7 @@ class SlantDownLines(LineCollection): name = 'slant_down' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.morph_bounds.x_bounds - y_bounds = dataset.morph_bounds.y_bounds + x_bounds, y_bounds = dataset.morph_bounds xmin, xmax = x_bounds xmid = xmin + x_bounds.range / 2 diff --git a/src/data_morph/shapes/lines/slant_up.py b/src/data_morph/shapes/lines/slant_up.py index e13563ba..266c85a6 100644 --- a/src/data_morph/shapes/lines/slant_up.py +++ b/src/data_morph/shapes/lines/slant_up.py @@ -27,8 +27,7 @@ class SlantUpLines(LineCollection): name = 'slant_up' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.morph_bounds.x_bounds - y_bounds = dataset.morph_bounds.y_bounds + x_bounds, y_bounds = dataset.morph_bounds xmin, xmax = x_bounds xmid = xmin + x_bounds.range / 2 diff --git a/src/data_morph/shapes/lines/vertical_lines.py b/src/data_morph/shapes/lines/vertical_lines.py index 74f72587..4982588b 100644 --- a/src/data_morph/shapes/lines/vertical_lines.py +++ b/src/data_morph/shapes/lines/vertical_lines.py @@ -29,8 +29,7 @@ class VerticalLines(LineCollection): name = 'v_lines' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds - y_bounds = dataset.data_bounds.y_bounds + x_bounds, y_bounds = dataset.data_bounds super().__init__( *[ diff --git a/src/data_morph/shapes/lines/wide_lines.py b/src/data_morph/shapes/lines/wide_lines.py index f919e2a6..c8df8032 100644 --- a/src/data_morph/shapes/lines/wide_lines.py +++ b/src/data_morph/shapes/lines/wide_lines.py @@ -27,8 +27,7 @@ class WideLines(LineCollection): name = 'wide_lines' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds - y_bounds = dataset.data_bounds.y_bounds + x_bounds, y_bounds = dataset.data_bounds offset = x_bounds.range / 5 lower = x_bounds[0] + offset diff --git a/src/data_morph/shapes/lines/x_lines.py b/src/data_morph/shapes/lines/x_lines.py index edf550dd..75a69f52 100644 --- a/src/data_morph/shapes/lines/x_lines.py +++ b/src/data_morph/shapes/lines/x_lines.py @@ -27,7 +27,6 @@ class XLines(LineCollection): name = 'x' def __init__(self, dataset: Dataset) -> None: - xmin, xmax = dataset.morph_bounds.x_bounds - ymin, ymax = dataset.morph_bounds.y_bounds + (xmin, xmax), (ymin, ymax) = dataset.morph_bounds super().__init__([[xmin, ymin], [xmax, ymax]], [[xmin, ymax], [xmax, ymin]]) diff --git a/src/data_morph/shapes/points/heart.py b/src/data_morph/shapes/points/heart.py index 71eda930..14580a38 100644 --- a/src/data_morph/shapes/points/heart.py +++ b/src/data_morph/shapes/points/heart.py @@ -35,7 +35,7 @@ class Heart(PointCollection): """ def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds + _, xmax = dataset.data_bounds.x_bounds x_shift, y_shift = dataset.data_bounds.center t = np.linspace(-3, 3, num=80) @@ -44,7 +44,7 @@ def __init__(self, dataset: Dataset) -> None: y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t) # scale by the half the widest width of the heart - scale_factor = (x_bounds[1] - x_shift) / 16 + scale_factor = (xmax - x_shift) / 16 super().__init__( *np.stack([x * scale_factor + x_shift, y * scale_factor + y_shift], axis=1) diff --git a/src/data_morph/shapes/points/parabola.py b/src/data_morph/shapes/points/parabola.py index ec2b0d41..f6a5dd24 100644 --- a/src/data_morph/shapes/points/parabola.py +++ b/src/data_morph/shapes/points/parabola.py @@ -29,17 +29,16 @@ class DownParabola(PointCollection): name = 'down_parab' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds + x_bounds, (ymin, ymax) = dataset.data_bounds xmin, xmax = x_bounds - xmid = xmax - x_bounds.range / 2 x_offset = x_bounds.range / 10 xmin += x_offset xmax -= x_offset - ymin, ymax = dataset.data_bounds.y_bounds - - poly = np.polynomial.Polynomial.fit([xmin, xmid, xmax], [ymin, ymax, ymin], 2) + poly = np.polynomial.Polynomial.fit( + [xmin, x_bounds.center, xmax], [ymin, ymax, ymin], 2 + ) super().__init__(*np.stack(poly.linspace(), axis=1)) @@ -67,17 +66,16 @@ class LeftParabola(PointCollection): name = 'left_parab' def __init__(self, dataset: Dataset) -> None: - y_bounds = dataset.data_bounds.y_bounds + (xmin, xmax), y_bounds = dataset.data_bounds ymin, ymax = y_bounds - ymid = ymax - y_bounds.range / 2 y_offset = y_bounds.range / 10 ymin += y_offset ymax -= y_offset - xmin, xmax = dataset.data_bounds.x_bounds - - poly = np.polynomial.Polynomial.fit([ymin, ymid, ymax], [xmin, xmax, xmin], 2) + poly = np.polynomial.Polynomial.fit( + [ymin, y_bounds.center, ymax], [xmin, xmax, xmin], 2 + ) super().__init__(*np.stack(poly.linspace()[::-1], axis=1)) @@ -105,17 +103,16 @@ class RightParabola(PointCollection): name = 'right_parab' def __init__(self, dataset: Dataset) -> None: - y_bounds = dataset.data_bounds.y_bounds + (xmin, xmax), y_bounds = dataset.data_bounds ymin, ymax = y_bounds - ymid = ymax - y_bounds.range / 2 y_offset = y_bounds.range / 10 ymin += y_offset ymax -= y_offset - xmin, xmax = dataset.data_bounds.x_bounds - - poly = np.polynomial.Polynomial.fit([ymin, ymid, ymax], [xmax, xmin, xmax], 2) + poly = np.polynomial.Polynomial.fit( + [ymin, y_bounds.center, ymax], [xmax, xmin, xmax], 2 + ) super().__init__(*np.stack(poly.linspace()[::-1], axis=1)) @@ -143,16 +140,15 @@ class UpParabola(PointCollection): name = 'up_parab' def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds + x_bounds, (ymin, ymax) = dataset.data_bounds xmin, xmax = x_bounds - xmid = xmax - x_bounds.range / 2 x_offset = x_bounds.range / 10 xmin += x_offset xmax -= x_offset - ymin, ymax = dataset.data_bounds.y_bounds - - poly = np.polynomial.Polynomial.fit([xmin, xmid, xmax], [ymax, ymin, ymax], 2) + poly = np.polynomial.Polynomial.fit( + [xmin, x_bounds.center, xmax], [ymax, ymin, ymax], 2 + ) super().__init__(*np.stack(poly.linspace(), axis=1)) diff --git a/src/data_morph/shapes/points/spade.py b/src/data_morph/shapes/points/spade.py index 4104a946..654c6e3a 100644 --- a/src/data_morph/shapes/points/spade.py +++ b/src/data_morph/shapes/points/spade.py @@ -30,14 +30,14 @@ class Spade(PointCollection): """ def __init__(self, dataset: Dataset) -> None: - x_bounds = dataset.data_bounds.x_bounds + _, xmax = dataset.data_bounds.x_bounds x_shift, y_shift = dataset.data_bounds.center # 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) + base_x, base_y = self._get_base(xmax, x_shift, y_shift) # combine all points x = np.concatenate((heart_points[:, 0], base_x), axis=0)