diff --git a/examples/animation/multiple_axes.py b/examples/animation/multiple_axes.py index 1fdc545d480d..ca75bea6169d 100644 --- a/examples/animation/multiple_axes.py +++ b/examples/animation/multiple_axes.py @@ -48,12 +48,12 @@ def animate(i): - pos = np.cos(i), np.sin(i) - point.set_data(*pos) x = np.linspace(0, i, int(i * 25 / np.pi)) sine.set_data(x, np.sin(x)) - con.xy1 = pos - con.xy2 = i, pos[1] + x, y = np.cos(i), np.sin(i) + point.set_data([x], [y]) + con.xy1 = x, y + con.xy2 = i, y return point, sine, con diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 35c1a1c75628..f843ccd49fee 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -1274,6 +1274,8 @@ def set_xdata(self, x): ---------- x : 1D array """ + if not np.iterable(x): + raise RuntimeError('x must be a sequence') self._xorig = copy.copy(x) self._invalidx = True self.stale = True @@ -1286,6 +1288,8 @@ def set_ydata(self, y): ---------- y : 1D array """ + if not np.iterable(y): + raise RuntimeError('y must be a sequence') self._yorig = copy.copy(y) self._invalidy = True self.stale = True diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py index e7002df8a558..4607d7872923 100644 --- a/lib/matplotlib/tests/test_lines.py +++ b/lib/matplotlib/tests/test_lines.py @@ -83,6 +83,19 @@ def test_set_line_coll_dash(): ax.contour(np.random.randn(20, 30), linestyles=[(0, (3, 3))]) +def test_invalid_line_data(): + with pytest.raises(RuntimeError, match='xdata must be'): + mlines.Line2D(0, []) + with pytest.raises(RuntimeError, match='ydata must be'): + mlines.Line2D([], 1) + + line = mlines.Line2D([], []) + with pytest.raises(RuntimeError, match='x must be'): + line.set_xdata(0) + with pytest.raises(RuntimeError, match='y must be'): + line.set_ydata(0) + + @image_comparison(['line_dashes'], remove_text=True) def test_line_dashes(): fig, ax = plt.subplots() diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 2f38bf48e9d8..27f153086ab9 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -871,7 +871,7 @@ def mean(vmin, vmax): # Return mean of values in x between *vmin* and *vmax* indmin, indmax = np.searchsorted(x, (vmin, vmax)) v = values[indmin:indmax].mean() - ln2.set_data(x, v) + ln2.set_data(x, np.full_like(x, v)) span = widgets.SpanSelector(ax, mean, direction='horizontal', onmove_callback=mean, @@ -888,7 +888,7 @@ def mean(vmin, vmax): assert span._get_animated_artists() == (ln, ln2) assert ln.stale is False assert ln2.stale - assert ln2.get_ydata() == 0.9547335049088455 + assert_allclose(ln2.get_ydata(), 0.9547335049088455) span.update() assert ln2.stale is False @@ -901,7 +901,7 @@ def mean(vmin, vmax): do_event(span, 'onmove', xdata=move_data[0], ydata=move_data[1], button=1) assert ln.stale is False assert ln2.stale - assert ln2.get_ydata() == -0.9424150707548072 + assert_allclose(ln2.get_ydata(), -0.9424150707548072) do_event(span, 'release', xdata=release_data[0], ydata=release_data[1], button=1) assert ln2.stale is False diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 935a3b014c16..af1994ca42b3 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -3426,7 +3426,8 @@ def extents(self, extents): # Update displayed handles self._corner_handles.set_data(*self.corners) self._edge_handles.set_data(*self.edge_centers) - self._center_handle.set_data(*self.center) + x, y = self.center + self._center_handle.set_data([x], [y]) self.set_visible(self._visible) self.update() diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index be1ccd6fb5d4..14511f4a8c2d 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -200,7 +200,7 @@ def __init__(self, xs, ys, zs, *args, **kwargs): Additional arguments are passed onto :func:`~matplotlib.lines.Line2D`. """ super().__init__([], [], *args, **kwargs) - self._verts3d = xs, ys, zs + self.set_data_3d(xs, ys, zs) def set_3d_properties(self, zs=0, zdir='z'): """ @@ -240,9 +240,11 @@ def set_data_3d(self, *args): Accepts x, y, z arguments or a single array-like (x, y, z) """ if len(args) == 1: - self._verts3d = args[0] - else: - self._verts3d = args + args = args[0] + for name, xyz in zip('xyz', args): + if not np.iterable(xyz): + raise RuntimeError(f'{name} must be a sequence') + self._verts3d = args self.stale = True def get_data_3d(self): diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index 39fcab38f63e..3d75aabb65eb 100644 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -47,7 +47,7 @@ def _tick_update_position(tick, tickxs, tickys, labelpos): tick.tick1line.set_linestyle('-') tick.tick1line.set_marker('') tick.tick1line.set_data(tickxs, tickys) - tick.gridline.set_data(0, 0) + tick.gridline.set_data([0], [0]) class Axis(maxis.XAxis): diff --git a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py index 10e6f58b3ccd..c8c8fbfa25a4 100644 --- a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py +++ b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py @@ -310,6 +310,23 @@ def test_plot_scalar(fig_test, fig_ref): ax2.plot(1, 1, "o") +def test_invalid_line_data(): + with pytest.raises(RuntimeError, match='x must be'): + art3d.Line3D(0, [], []) + with pytest.raises(RuntimeError, match='y must be'): + art3d.Line3D([], 0, []) + with pytest.raises(RuntimeError, match='z must be'): + art3d.Line3D([], [], 0) + + line = art3d.Line3D([], [], []) + with pytest.raises(RuntimeError, match='x must be'): + line.set_data_3d(0, [], []) + with pytest.raises(RuntimeError, match='y must be'): + line.set_data_3d([], 0, []) + with pytest.raises(RuntimeError, match='z must be'): + line.set_data_3d([], [], 0) + + @mpl3d_image_comparison(['mixedsubplot.png']) def test_mixedsubplots(): def f(t):