From 102c91d64a7d9c4c7b53368edaa112a6cb5b1993 Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Thu, 15 Oct 2026 11:19:47 +1000 Subject: [PATCH] fix(graphics): ignore sign of scalar in expand_dims, document reversed limits A negative scalar previously produced reversed limits (-3 -> [3,-3,...]), silently inverting the axes. A scalar is symmetric about zero, so use abs(). Document that min > max in the 2/4/6 element forms is passed through and matplotlib inverts the axis. Add test_expand_dims. Co-Authored-By: Claude Sonnet 5.5 --- spatialmath/base/graphics.py | 8 ++++++++ tests/base/test_graphics.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/spatialmath/base/graphics.py b/spatialmath/base/graphics.py index c51d7f94..1dd63b14 100644 --- a/spatialmath/base/graphics.py +++ b/spatialmath/base/graphics.py @@ -1708,11 +1708,18 @@ def expand_dims(dim: ArrayLike = None, nd: int = 2) -> NDArray: * A -> [-A, A, -A, A, -A, A] * [A,B] -> [A, B, A, B, A, B] * [A,B,C,D,E,F] -> [A, B, C, D, E, F] + + A scalar is symmetric about zero, so its sign is ignored: ``-A`` is the + same as ``A``. For the other forms the values are returned as given and + no ordering check is made. If a minimum is greater than the + corresponding maximum, matplotlib will invert that axis when the limits + are applied, which is a convenient way to flip an axis direction. """ dim = smb.getvector(dim) if nd == 2: if len(dim) == 1: + dim = abs(dim) return np.r_[-dim, dim, -dim, dim] elif len(dim) == 2: return np.r_[dim[0], dim[1], dim[0], dim[1]] @@ -1722,6 +1729,7 @@ def expand_dims(dim: ArrayLike = None, nd: int = 2) -> NDArray: raise ValueError("bad dimension specified") elif nd == 3: if len(dim) == 1: + dim = abs(dim) return np.r_[-dim, dim, -dim, dim, -dim, dim] elif len(dim) == 2: return np.r_[dim[0], dim[1], dim[0], dim[1], dim[0], dim[1]] diff --git a/tests/base/test_graphics.py b/tests/base/test_graphics.py index 552ebdb0..d19bb6bf 100644 --- a/tests/base/test_graphics.py +++ b/tests/base/test_graphics.py @@ -13,6 +13,23 @@ class TestGraphics(unittest.TestCase): def teardown_method(self, method): plt.close("all") + def test_expand_dims(self): + np.testing.assert_array_equal(expand_dims(3), [-3, 3, -3, 3]) + np.testing.assert_array_equal(expand_dims(-3), [-3, 3, -3, 3]) + np.testing.assert_array_equal(expand_dims([1, 2]), [1, 2, 1, 2]) + np.testing.assert_array_equal(expand_dims([1, 2, 3, 4]), [1, 2, 3, 4]) + # reversed limits are passed through, matplotlib inverts the axis + np.testing.assert_array_equal(expand_dims([2, 1]), [2, 1, 2, 1]) + + np.testing.assert_array_equal(expand_dims(-3, nd=3), [-3, 3, -3, 3, -3, 3]) + np.testing.assert_array_equal(expand_dims([1, 2], nd=3), [1, 2] * 3) + np.testing.assert_array_equal(expand_dims([1, 2, 3, 4, 5, 6], nd=3), [1, 2, 3, 4, 5, 6]) + + with self.assertRaises(ValueError): + expand_dims([1, 2, 3]) + with self.assertRaises(ValueError): + expand_dims([1, 2, 3, 4], nd=3) + @pytest.mark.skipif( sys.platform.startswith("darwin") and sys.version_info < (3, 11), reason="tkinter bug with mac",