Skip to content

Commit e440ee7

Browse files
authored
Reduce redundancy in shape factory by adding names (#242)
1 parent 0a7421a commit e440ee7

File tree

12 files changed

+78
-65
lines changed

12 files changed

+78
-65
lines changed

docs/tutorials/shape-creation.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,18 @@ to calculate its position and scale:
6161

6262
class XLines(LineCollection):
6363

64+
name = 'x'
65+
6466
def __init__(self, dataset: Dataset) -> None:
6567
xmin, xmax = dataset.morph_bounds.x_bounds
6668
ymin, ymax = dataset.morph_bounds.y_bounds
6769

6870
super().__init__([[xmin, ymin], [xmax, ymax]], [[xmin, ymax], [xmax, ymin]])
6971

70-
def __str__(self) -> str:
71-
return 'x'
7272

7373
Since we inherit from :class:`.LineCollection` here, we don't need to define
7474
the ``distance()`` and ``plot()`` methods (unless we want to override them).
75-
We do override the ``__str__()`` method here since the default will result in
75+
We do set the ``name`` attribute here since the default will result in
7676
a value of ``xlines`` and ``x`` makes more sense for use in the documentation
7777
(see :class:`.ShapeFactory`).
7878

@@ -89,8 +89,8 @@ For the ``data-morph`` CLI to find your shape, you need to register it with the
8989
2. Add your shape to ``__all__`` in that module's ``__init__.py`` (*e.g.*, use
9090
``src/data_morph/shapes/points/__init__.py`` for a new shape inheriting from
9191
:class:`.PointCollection`).
92-
3. Add an entry to the ``ShapeFactory._SHAPE_MAPPING`` dictionary in
93-
``src/data_morph/shapes/factory.py``.
92+
3. Add an entry to the ``ShapeFactory._SHAPE_CLASSES`` tuple in
93+
``src/data_morph/shapes/factory.py``, preserving alphabetical order.
9494

9595
Test out the shape
9696
------------------

src/data_morph/shapes/bases/shape.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@
1313
class Shape(ABC):
1414
"""Abstract base class for a shape."""
1515

16+
name: str | None = None
17+
"""The display name for the shape, if the lowercased class name is not desired."""
18+
19+
@classmethod
20+
def get_name(cls) -> str:
21+
"""
22+
Get the name of the shape.
23+
24+
Returns
25+
-------
26+
str
27+
The name of the shape.
28+
"""
29+
return cls.name or cls.__name__.lower()
30+
1631
def __repr__(self) -> str:
1732
"""
1833
Return string representation of the shape.
@@ -32,8 +47,12 @@ def __str__(self) -> str:
3247
-------
3348
str
3449
The human-readable string representation of the shape.
50+
51+
See Also
52+
--------
53+
get_name : This calls the :meth:`.get_name` class method.
3554
"""
36-
return self.__class__.__name__.lower()
55+
return self.get_name()
3756

3857
@abstractmethod
3958
def distance(self, x: Number, y: Number) -> float:

src/data_morph/shapes/factory.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,33 +57,39 @@ class ShapeFactory:
5757
The starting dataset to morph into other shapes.
5858
"""
5959

60+
_SHAPE_CLASSES: tuple[type[Shape]] = (
61+
Bullseye,
62+
Circle,
63+
Club,
64+
Diamond,
65+
DotsGrid,
66+
DownParabola,
67+
Heart,
68+
HighLines,
69+
HorizontalLines,
70+
LeftParabola,
71+
Rectangle,
72+
RightParabola,
73+
Rings,
74+
Scatter,
75+
SlantDownLines,
76+
SlantUpLines,
77+
Spade,
78+
Star,
79+
UpParabola,
80+
VerticalLines,
81+
WideLines,
82+
XLines,
83+
)
84+
"""New shape classes must be registered here."""
85+
6086
_SHAPE_MAPPING: ClassVar[dict[str, type[Shape]]] = {
61-
'bullseye': Bullseye,
62-
'circle': Circle,
63-
'high_lines': HighLines,
64-
'h_lines': HorizontalLines,
65-
'slant_down': SlantDownLines,
66-
'slant_up': SlantUpLines,
67-
'v_lines': VerticalLines,
68-
'wide_lines': WideLines,
69-
'x': XLines,
70-
'dots': DotsGrid,
71-
'down_parab': DownParabola,
72-
'heart': Heart,
73-
'left_parab': LeftParabola,
74-
'scatter': Scatter,
75-
'right_parab': RightParabola,
76-
'up_parab': UpParabola,
77-
'diamond': Diamond,
78-
'rectangle': Rectangle,
79-
'rings': Rings,
80-
'star': Star,
81-
'club': Club,
82-
'spade': Spade,
87+
shape_cls.get_name(): shape_cls for shape_cls in _SHAPE_CLASSES
8388
}
89+
"""Mapping of shape display names to classes."""
8490

8591
AVAILABLE_SHAPES: list[str] = sorted(_SHAPE_MAPPING.keys())
86-
"""list[str]: The list of available shapes, which can be visualized with
92+
"""The list of available shapes, which can be visualized with
8793
:meth:`.plot_available_shapes`."""
8894

8995
def __init__(self, dataset: Dataset) -> None:

src/data_morph/shapes/lines/high_lines.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class HighLines(LineCollection):
2424
The starting dataset to morph into other shapes.
2525
"""
2626

27+
name = 'high_lines'
28+
2729
def __init__(self, dataset: Dataset) -> None:
2830
x_bounds = dataset.data_bounds.x_bounds
2931
y_bounds = dataset.data_bounds.y_bounds
@@ -36,6 +38,3 @@ def __init__(self, dataset: Dataset) -> None:
3638
[[x_bounds[0], lower], [x_bounds[1], lower]],
3739
[[x_bounds[0], upper], [x_bounds[1], upper]],
3840
)
39-
40-
def __str__(self) -> str:
41-
return 'high_lines'

src/data_morph/shapes/lines/horizontal_lines.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class HorizontalLines(LineCollection):
2626
The starting dataset to morph into other shapes.
2727
"""
2828

29+
name = 'h_lines'
30+
2931
def __init__(self, dataset: Dataset) -> None:
3032
x_bounds = dataset.data_bounds.x_bounds
3133
y_bounds = dataset.data_bounds.y_bounds
@@ -36,6 +38,3 @@ def __init__(self, dataset: Dataset) -> None:
3638
for y in np.linspace(y_bounds[0], y_bounds[1], 5)
3739
]
3840
)
39-
40-
def __str__(self) -> str:
41-
return 'h_lines'

src/data_morph/shapes/lines/slant_down.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class SlantDownLines(LineCollection):
2424
The starting dataset to morph into other shapes.
2525
"""
2626

27+
name = 'slant_down'
28+
2729
def __init__(self, dataset: Dataset) -> None:
2830
x_bounds = dataset.morph_bounds.x_bounds
2931
y_bounds = dataset.morph_bounds.y_bounds
@@ -43,6 +45,3 @@ def __init__(self, dataset: Dataset) -> None:
4345
[[xmin + x_offset, ymax], [xmax, ymin + y_offset]],
4446
[[xmid, ymax], [xmax, ymid]],
4547
)
46-
47-
def __str__(self) -> str:
48-
return 'slant_down'

src/data_morph/shapes/lines/slant_up.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class SlantUpLines(LineCollection):
2424
The starting dataset to morph into other shapes.
2525
"""
2626

27+
name = 'slant_up'
28+
2729
def __init__(self, dataset: Dataset) -> None:
2830
x_bounds = dataset.morph_bounds.x_bounds
2931
y_bounds = dataset.morph_bounds.y_bounds
@@ -43,6 +45,3 @@ def __init__(self, dataset: Dataset) -> None:
4345
[[xmin + x_offset, ymin], [xmax, ymid + y_offset]],
4446
[[xmid, ymin], [xmax, ymid]],
4547
)
46-
47-
def __str__(self) -> str:
48-
return 'slant_up'

src/data_morph/shapes/lines/vertical_lines.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class VerticalLines(LineCollection):
2626
The starting dataset to morph into other shapes.
2727
"""
2828

29+
name = 'v_lines'
30+
2931
def __init__(self, dataset: Dataset) -> None:
3032
x_bounds = dataset.data_bounds.x_bounds
3133
y_bounds = dataset.data_bounds.y_bounds
@@ -36,6 +38,3 @@ def __init__(self, dataset: Dataset) -> None:
3638
for x in np.linspace(x_bounds[0], x_bounds[1], 5)
3739
]
3840
)
39-
40-
def __str__(self) -> str:
41-
return 'v_lines'

src/data_morph/shapes/lines/wide_lines.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class WideLines(LineCollection):
2424
The starting dataset to morph into other shapes.
2525
"""
2626

27+
name = 'wide_lines'
28+
2729
def __init__(self, dataset: Dataset) -> None:
2830
x_bounds = dataset.data_bounds.x_bounds
2931
y_bounds = dataset.data_bounds.y_bounds
@@ -36,6 +38,3 @@ def __init__(self, dataset: Dataset) -> None:
3638
[[lower, y_bounds[0]], [lower, y_bounds[1]]],
3739
[[upper, y_bounds[0]], [upper, y_bounds[1]]],
3840
)
39-
40-
def __str__(self) -> str:
41-
return 'wide_lines'

src/data_morph/shapes/lines/x_lines.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,10 @@ class XLines(LineCollection):
2424
The starting dataset to morph into other shapes.
2525
"""
2626

27+
name = 'x'
28+
2729
def __init__(self, dataset: Dataset) -> None:
2830
xmin, xmax = dataset.morph_bounds.x_bounds
2931
ymin, ymax = dataset.morph_bounds.y_bounds
3032

3133
super().__init__([[xmin, ymin], [xmax, ymax]], [[xmin, ymax], [xmax, ymin]])
32-
33-
def __str__(self) -> str:
34-
return 'x'

0 commit comments

Comments
 (0)