Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/tutorials/shape-creation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ shape inherits from :class:`.LineCollection` and uses the morph bounds
Since we inherit from :class:`.LineCollection` here, we don't need to define
the ``distance()`` and ``plot()`` methods (unless we want to override them).

.. tip::
You can use the :func:`.plot_shape_on_dataset` function to visualize your
shape's positioning relative to a given dataset. Your shape can exceed the data
bounds (:attr:`.Dataset.data_bounds`); however, it should not exceed the morph
bounds (:attr:`.Dataset.morph_bounds`):

.. plot::
:scale: 75
:include-source:
:caption:
Visualization of the :class:`.XLines` shape when calculated based on the
music :class:`.Dataset`, with the dataset's bounds.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import XLines


dataset = DataLoader.load_dataset('music')
shape = XLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=True, alpha=0.1)

Test out the shape
------------------

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,6 @@ exclude = [ # don't report on checks for these
'\.__repr__$',
'\.__str__$',
]
override_SS05 = [ # allow docstrings to start with these words
'^Unambiguous ',
]
5 changes: 4 additions & 1 deletion src/data_morph/data/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def plot(
ax: Axes | None = None,
show_bounds: bool = True,
title: str | None = 'default',
alpha: Number = 1,
) -> Axes:
"""
Plot the dataset and its bounds.
Expand All @@ -214,6 +215,8 @@ def plot(
title : str | ``None``, optional
Title to use for the plot. The default will call ``str()`` on the
Dataset. Pass ``None`` to leave the plot untitled.
alpha : Number, default ``1``
The transparency to use for the points in the plot.

Returns
-------
Expand All @@ -225,7 +228,7 @@ def plot(
fig.get_layout_engine().set(w_pad=0.2, h_pad=0.2)

ax.axis('equal')
ax.scatter(self.data.x, self.data.y, s=2, color='black')
ax.scatter(self.data.x, self.data.y, s=2, color='black', alpha=alpha)
ax.set(xlabel='', ylabel='', title=self if title == 'default' else title)

if show_bounds:
Expand Down
79 changes: 79 additions & 0 deletions src/data_morph/plotting/diagnostics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""Diagnostic plot to visualize a shape superimposed on the dataset."""

from __future__ import annotations

from typing import TYPE_CHECKING

from ..plotting.style import plot_with_custom_style

if TYPE_CHECKING:
from numbers import Number

from matplotlib.axes import Axes

from ..data.dataset import Dataset
from ..shapes.bases.shape import Shape


@plot_with_custom_style
def plot_shape_on_dataset(
dataset: Dataset,
shape: Shape,
show_bounds: bool = False,
alpha: Number = 0.25,
) -> Axes:
"""
Plot a shape superimposed on a dataset to evaluate heuristics.

Parameters
----------
dataset : Dataset
The dataset that ``shape`` was instantiated with.
shape : Shape
The shape that was instantiated with ``dataset``.
show_bounds : bool, default ``False``
Whether to include the dataset's bounds in the plot.
alpha : Number, default ``0.25``
The transparency to use for the dataset's points.

Returns
-------
matplotlib.axes.Axes
The :class:`~matplotlib.axes.Axes` object containing the plot.

Examples
--------

.. plot::
:scale: 75
:include-source:
:caption:
Visualization of the :class:`.Star` shape when calculated based on the
music :class:`.Dataset`, with the dataset's bounds.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import Star

dataset = DataLoader.load_dataset('music')
shape = Star(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=True, alpha=0.1)

.. plot::
:scale: 75
:include-source:
:caption:
Visualization of the :class:`.Heart` shape when calculated based on the
music :class:`.Dataset`, without the dataset's bounds.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.points import Heart

dataset = DataLoader.load_dataset('music')
shape = Heart(dataset)
plot_shape_on_dataset(dataset, shape, alpha=0.1)
"""
ax = dataset.plot(show_bounds=show_bounds, title=None, alpha=alpha)
shape.plot(ax=ax)
return ax
5 changes: 4 additions & 1 deletion src/data_morph/shapes/circles/bullseye.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ class Bullseye(Rings):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.circles import Bullseye

_ = Bullseye(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Bullseye(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

See Also
--------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/circles/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ class Circle(Shape):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.circles import Circle

_ = Circle(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Circle(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/circles/rings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ class Rings(Shape):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.circles import Rings

_ = Rings(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Rings(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
6 changes: 4 additions & 2 deletions src/data_morph/shapes/lines/diamond.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ class Diamond(LineCollection):
:caption:
This shape is generated using the panda dataset.

import matplotlib.pyplot as plt
from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import Diamond

_ = Diamond(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Diamond(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/high_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class HighLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import HighLines

_ = HighLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = HighLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/horizontal_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ class HorizontalLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import HorizontalLines

_ = HorizontalLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = HorizontalLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
6 changes: 4 additions & 2 deletions src/data_morph/shapes/lines/rectangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ class Rectangle(LineCollection):
:caption:
This shape is generated using the panda dataset.

import matplotlib.pyplot as plt
from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import Rectangle

_ = Rectangle(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Rectangle(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/slant_down.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class SlantDownLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import SlantDownLines

_ = SlantDownLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = SlantDownLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/slant_up.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class SlantUpLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import SlantUpLines

_ = SlantUpLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = SlantUpLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
6 changes: 4 additions & 2 deletions src/data_morph/shapes/lines/star.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ class Star(LineCollection):
:caption:
This shape is generated using the panda dataset.

import matplotlib.pyplot as plt
from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import Star

_ = Star(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Star(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/vertical_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ class VerticalLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import VerticalLines

_ = VerticalLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = VerticalLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/wide_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class WideLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import WideLines

_ = WideLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = WideLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/lines/x_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class XLines(LineCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.lines import XLines

_ = XLines(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = XLines(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/points/club.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ class Club(PointCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.points import Club

_ = Club(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = Club(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand Down
5 changes: 4 additions & 1 deletion src/data_morph/shapes/points/dots_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ class DotsGrid(PointCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.points import DotsGrid

_ = DotsGrid(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = DotsGrid(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.1)

Parameters
----------
Expand Down
23 changes: 21 additions & 2 deletions src/data_morph/shapes/points/figure_eight.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ class FigureEight(PointCollection):
This shape is generated using the panda dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.points import FigureEight

_ = FigureEight(DataLoader.load_dataset('panda')).plot()
dataset = DataLoader.load_dataset('panda')
shape = FigureEight(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.25)

Parameters
----------
Expand All @@ -30,7 +33,23 @@ class FigureEight(PointCollection):
Notes
-----
This shape uses the formula for the `Lemniscate of Bernoulli
<https://en.wikipedia.org/wiki/Lemniscate_of_Bernoulli>`_.
<https://en.wikipedia.org/wiki/Lemniscate_of_Bernoulli>`_. It will orient itself
vertically or horizontally depending on which direction has a larger range in the
input dataset. For example, the panda dataset used above resulted in a horizontal
orientation, but the music dataset results in a vertical orientation:

.. plot::
:scale: 75
:caption:
This shape is generated using the music dataset.

from data_morph.data.loader import DataLoader
from data_morph.plotting.diagnostics import plot_shape_on_dataset
from data_morph.shapes.points import FigureEight

dataset = DataLoader.load_dataset('music')
shape = FigureEight(dataset)
plot_shape_on_dataset(dataset, shape, show_bounds=False, alpha=0.1)
"""

name = 'figure_eight'
Expand Down
Loading
Loading