From 8c8db31fc94e1db07d121e13641bd82e16be086b Mon Sep 17 00:00:00 2001 From: MengAiDev <3463526515@qq.com> Date: Thu, 14 Aug 2025 13:35:40 +0800 Subject: [PATCH 1/5] Fix Line3DCollection with autolim=True for lines of different lengths When using Line3DCollection with autolim=True, the code was trying to convert ragged arrays (lines with different numbers of points) directly to a numpy array, which would fail. This fix extracts coordinates separately to avoid the issue. Fixes #30418 --- lib/mpl_toolkits/mplot3d/axes3d.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index c56e4c6b7039..f4549b3064c9 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2890,8 +2890,10 @@ def add_collection3d(self, col, zs=0, zdir='z', autolim=True, *, if autolim: if isinstance(col, art3d.Line3DCollection): - self.auto_scale_xyz(*np.array(col._segments3d).transpose(), - had_data=had_data) + # Handle ragged arrays in Line3DCollection by extracting coordinates separately + all_points = np.concatenate(col._segments3d) + self.auto_scale_xyz(all_points[:, 0], all_points[:, 1], + all_points[:, 2], had_data=had_data) elif isinstance(col, art3d.Poly3DCollection): self.auto_scale_xyz(col._faces[..., 0], col._faces[..., 1], From eecd9f8a56466662c4a61eb815084ea27c8cc8ef Mon Sep 17 00:00:00 2001 From: MengAiDev <3463526515@qq.com> Date: Thu, 14 Aug 2025 17:34:24 +0800 Subject: [PATCH 2/5] fix lint --- lib/mpl_toolkits/mplot3d/axes3d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index f4549b3064c9..a3f92e3855ce 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2892,7 +2892,7 @@ def add_collection3d(self, col, zs=0, zdir='z', autolim=True, *, if isinstance(col, art3d.Line3DCollection): # Handle ragged arrays in Line3DCollection by extracting coordinates separately all_points = np.concatenate(col._segments3d) - self.auto_scale_xyz(all_points[:, 0], all_points[:, 1], + self.auto_scale_xyz(all_points[:, 0], all_points[:, 1], all_points[:, 2], had_data=had_data) elif isinstance(col, art3d.Poly3DCollection): self.auto_scale_xyz(col._faces[..., 0], From dc320e956b1e9cbe3ac9119bbe4cd0f39cb0630d Mon Sep 17 00:00:00 2001 From: MengAiDev <3463526515@qq.com> Date: Tue, 19 Aug 2025 16:37:49 +0800 Subject: [PATCH 3/5] fix lint --- lib/mpl_toolkits/mplot3d/axes3d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index a3f92e3855ce..3122b64bde73 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2890,7 +2890,7 @@ def add_collection3d(self, col, zs=0, zdir='z', autolim=True, *, if autolim: if isinstance(col, art3d.Line3DCollection): - # Handle ragged arrays in Line3DCollection by extracting coordinates separately + # Handle ragged arrays by extracting coordinates separately all_points = np.concatenate(col._segments3d) self.auto_scale_xyz(all_points[:, 0], all_points[:, 1], all_points[:, 2], had_data=had_data) From 2e72b5aeb7332b187fe4f651004ee7a181532ced Mon Sep 17 00:00:00 2001 From: MengAiDev <3463526515@qq.com> Date: Wed, 20 Aug 2025 08:49:39 +0800 Subject: [PATCH 4/5] Add test for Line3DCollection with autolim=True and ragged arrays --- .../tests/test_line3dcollection_ragged.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py diff --git a/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py b/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py new file mode 100644 index 000000000000..5c489f3d2fd4 --- /dev/null +++ b/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py @@ -0,0 +1,27 @@ +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import art3d + + +def test_line3dcollection_autolim_ragged(): + """Test Line3DCollection with autolim=True and lines of different lengths.""" + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + + # Create lines with different numbers of points (ragged arrays) + edges = [ + [(0, 0, 0), (1, 1, 1), (2, 2, 2)], # 3 points + [(0, 1, 0), (1, 2, 1)], # 2 points + [(1, 0, 1), (2, 1, 2), (3, 2, 3), (4, 3, 4)] # 4 points + ] + + # This should not raise an exception with the fix + collections = ax.add_collection3d(art3d.Line3DCollection(edges), autolim=True) + + # Check that limits were computed correctly with margins + # The limits should include all points with default margins + assert np.allclose(ax.get_xlim3d(), (-0.08333333333333333, 4.083333333333333)) + assert np.allclose(ax.get_ylim3d(), (-0.0625, 3.0625)) + assert np.allclose(ax.get_zlim3d(), (-0.08333333333333333, 4.083333333333333)) + + plt.close(fig) From c6eaa05e8e2c8312217c4120f393cfe331989196 Mon Sep 17 00:00:00 2001 From: MengAiDev <3463526515@qq.com> Date: Wed, 20 Aug 2025 10:49:21 +0800 Subject: [PATCH 5/5] move test --- lib/mpl_toolkits/mplot3d/tests/test_axes3d.py | 24 +++++++++++++++++ .../tests/test_line3dcollection_ragged.py | 27 ------------------- 2 files changed, 24 insertions(+), 27 deletions(-) delete mode 100644 lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py diff --git a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py index e6d11f793b46..791fa5bb3fbd 100644 --- a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py +++ b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py @@ -2689,3 +2689,27 @@ def test_ndarray_color_kwargs_value_error(): ax = fig.add_subplot(111, projection='3d') ax.scatter(1, 0, 0, color=np.array([0, 0, 0, 1])) fig.canvas.draw() + + +def test_line3dcollection_autolim_ragged(): + """Test Line3DCollection with autolim=True and lines of different lengths.""" + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + + # Create lines with different numbers of points (ragged arrays) + edges = [ + [(0, 0, 0), (1, 1, 1), (2, 2, 2)], # 3 points + [(0, 1, 0), (1, 2, 1)], # 2 points + [(1, 0, 1), (2, 1, 2), (3, 2, 3), (4, 3, 4)] # 4 points + ] + + # This should not raise an exception with the fix + collections = ax.add_collection3d(art3d.Line3DCollection(edges), autolim=True) + + # Check that limits were computed correctly with margins + # The limits should include all points with default margins + assert np.allclose(ax.get_xlim3d(), (-0.08333333333333333, 4.083333333333333)) + assert np.allclose(ax.get_ylim3d(), (-0.0625, 3.0625)) + assert np.allclose(ax.get_zlim3d(), (-0.08333333333333333, 4.083333333333333)) + + plt.close(fig) diff --git a/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py b/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py deleted file mode 100644 index 5c489f3d2fd4..000000000000 --- a/lib/mpl_toolkits/mplot3d/tests/test_line3dcollection_ragged.py +++ /dev/null @@ -1,27 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from mpl_toolkits.mplot3d import art3d - - -def test_line3dcollection_autolim_ragged(): - """Test Line3DCollection with autolim=True and lines of different lengths.""" - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - - # Create lines with different numbers of points (ragged arrays) - edges = [ - [(0, 0, 0), (1, 1, 1), (2, 2, 2)], # 3 points - [(0, 1, 0), (1, 2, 1)], # 2 points - [(1, 0, 1), (2, 1, 2), (3, 2, 3), (4, 3, 4)] # 4 points - ] - - # This should not raise an exception with the fix - collections = ax.add_collection3d(art3d.Line3DCollection(edges), autolim=True) - - # Check that limits were computed correctly with margins - # The limits should include all points with default margins - assert np.allclose(ax.get_xlim3d(), (-0.08333333333333333, 4.083333333333333)) - assert np.allclose(ax.get_ylim3d(), (-0.0625, 3.0625)) - assert np.allclose(ax.get_zlim3d(), (-0.08333333333333333, 4.083333333333333)) - - plt.close(fig)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: