Skip to content

Commit a624b59

Browse files
authored
fix(graphics): accept unspecified dimensions in expand_dims (#270)
Fixes #261. `expand_dims()` raises `TypeError` even though `dim=None` is its documented default. Return `None` for an unspecified extent so callers can choose autoscaling or obtain limits elsewhere. Update the argument and return annotations and docstring to describe this behavior. Validate `nd` before returning, so unsupported dimensions still raise `ValueError`, including when `dim` is `None`; zero remains an explicit extent. Add regressions for omitted and explicit `None` in 2D/3D, explicit numeric extents, malformed vectors, and unsupported dimensions. Preserve the negative-scalar and reversed-limit behavior from #262 and its regression tests. Validation on this branch including upstream master `824a459` (`MPLBACKEND=Agg`): - Python 3.12.14 full suite: **476 passed, 3 skipped**, with 71 subtests passed and 23 warnings. - Graphics tests on Python 3.10.12 and 3.12.14: **21 passed**, with 8 subtests passed on each version. - Repository pre-commit hooks (Black 23.10.0, EOF, debug statements, trailing whitespace) and `git diff --check` pass. Black also wraps existing long lines in the touched graphics module and test file. The existing internal callers already guard `None`. Downstream bdsim behavior has not been tested; the `scale=None` timing change noted in #261 remains applicable. Signed-off-by: 李永祺 <doribelove@gmail.com>
1 parent a3b6492 commit a624b59

2 files changed

Lines changed: 47 additions & 9 deletions

File tree

‎spatialmath/base/graphics.py‎

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,10 @@ def _axes_dimensions(ax: plt.Axes) -> int:
15131513
# handle the case of Animate objects pretending to be Axes
15141514
classname = ax.__class__.__name__
15151515
base_classes = ax.__class__.__bases__
1516-
if classname in ("Axes3DSubplot", "Animate") or any(base_class.__name__ in ("Axes3DSubplot", "Animate") for base_class in base_classes):
1516+
if classname in ("Axes3DSubplot", "Animate") or any(
1517+
base_class.__name__ in ("Axes3DSubplot", "Animate")
1518+
for base_class in base_classes
1519+
):
15171520
return 3
15181521
elif classname in ("AxesSubplot", "Animate2"):
15191522
return 2
@@ -1736,20 +1739,24 @@ def plotvol3(
17361739
ax._plotvol = True
17371740
return ax
17381741

1739-
def expand_dims(dim: ArrayLike = None, nd: int = 2) -> NDArray:
1742+
def expand_dims(dim: ArrayLike | None = None, nd: int = 2) -> NDArray | None:
17401743
"""
17411744
Expand compact axis dimensions
17421745
1743-
:param dim: dimensions, defaults to None
1746+
:param dim: dimensions, or None if unspecified, defaults to None
17441747
:type dim: scalar, array_like(2), array_like(4), array_like(6), optional
1745-
:param nd: number of axes dimensions, defaults to 2
1748+
:param nd: number of axes dimensions (2 or 3), defaults to 2
17461749
:type nd: int, optional
17471750
:raises ValueError: bad arguments
1748-
:return: 2d or 3d dimensions vector
1749-
:rtype: ndarray(4) or ndarray(6)
1751+
:return: 2d or 3d dimensions vector, or None if unspecified
1752+
:rtype: ndarray(4), ndarray(6), or None
17501753
17511754
Compute bounding dimensions for plots from shorthand notation.
17521755
1756+
``None`` is returned unchanged so the caller can choose whether to
1757+
autoscale or obtain dimensions from another source. No default extent
1758+
is inferred.
1759+
17531760
If ``nd==2``, [xmin, xmax, ymin, ymax]:
17541761
* A -> [-A, A, -A, A]
17551762
* [A,B] -> [A, B, A, B]
@@ -1766,6 +1773,11 @@ def expand_dims(dim: ArrayLike = None, nd: int = 2) -> NDArray:
17661773
corresponding maximum, matplotlib will invert that axis when the limits
17671774
are applied, which is a convenient way to flip an axis direction.
17681775
"""
1776+
if nd not in (2, 3):
1777+
raise ValueError("nd is 2 or 3")
1778+
if dim is None:
1779+
return None
1780+
17691781
dim = smb.getvector(dim)
17701782

17711783
if nd == 2:
@@ -1788,8 +1800,6 @@ def expand_dims(dim: ArrayLike = None, nd: int = 2) -> NDArray:
17881800
return dim
17891801
else:
17901802
raise ValueError("bad dimension specified")
1791-
else:
1792-
raise ValueError("nd is 2 or 3")
17931803

17941804
def set_window_title(fig: plt.Figure, title: str) -> bool:
17951805
"""

‎tests/base/test_graphics.py‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,32 @@ class TestGraphics(unittest.TestCase):
4646
def teardown_method(self, method):
4747
plt.close("all")
4848

49+
def test_expand_dims_unspecified(self):
50+
self.assertIsNone(expand_dims())
51+
for nd in (2, 3):
52+
with self.subTest(nd=nd):
53+
self.assertIsNone(expand_dims(nd=nd))
54+
self.assertIsNone(expand_dims(None, nd=nd))
55+
56+
def test_expand_dims_specified(self):
57+
for nd in (2, 3):
58+
with self.subTest(nd=nd):
59+
# Zero is an explicit extent, not an unspecified one.
60+
np.testing.assert_array_equal(expand_dims(0, nd), [0, 0] * nd)
61+
np.testing.assert_array_equal(expand_dims(3, nd), [-3, 3] * nd)
62+
np.testing.assert_array_equal(expand_dims([-2, 5], nd), [-2, 5] * nd)
63+
limits = np.arange(2 * nd)
64+
np.testing.assert_array_equal(expand_dims(limits, nd), limits)
65+
with self.assertRaises(ValueError):
66+
expand_dims([1, 2, 3], nd)
67+
68+
def test_expand_dims_invalid_nd(self):
69+
for nd in (1, 4):
70+
for dim in (None, 1):
71+
with self.subTest(nd=nd, dim=dim):
72+
with self.assertRaisesRegex(ValueError, "nd is 2 or 3"):
73+
expand_dims(dim, nd)
74+
4975
def test_expand_dims(self):
5076
np.testing.assert_array_equal(expand_dims(3), [-3, 3, -3, 3])
5177
np.testing.assert_array_equal(expand_dims(-3), [-3, 3, -3, 3])
@@ -56,7 +82,9 @@ def test_expand_dims(self):
5682

5783
np.testing.assert_array_equal(expand_dims(-3, nd=3), [-3, 3, -3, 3, -3, 3])
5884
np.testing.assert_array_equal(expand_dims([1, 2], nd=3), [1, 2] * 3)
59-
np.testing.assert_array_equal(expand_dims([1, 2, 3, 4, 5, 6], nd=3), [1, 2, 3, 4, 5, 6])
85+
np.testing.assert_array_equal(
86+
expand_dims([1, 2, 3, 4, 5, 6], nd=3), [1, 2, 3, 4, 5, 6]
87+
)
6088

6189
with self.assertRaises(ValueError):
6290
expand_dims([1, 2, 3])

0 commit comments

Comments
 (0)