Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/mpl_toolkits/mplot3d/art3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,12 @@ def draw(self, renderer):
if self._axlim_clip:
scale_mask |= _viewlim_mask(*self._verts3d, self.axes)
if np.any(scale_mask):
# np.shape rather than .shape: set_data_3d documents its
# parameters as array-like and stores whatever it is given, so
# _verts3d can hold lists or tuples.
mask = np.broadcast_to(
scale_mask,
(len(self._verts3d), *self._verts3d[0].shape)
(len(self._verts3d), *np.shape(self._verts3d[0]))
)
xs3d, ys3d, zs3d = np.ma.array(self._verts3d,
dtype=float, mask=mask).filled(np.nan)
Expand Down
36 changes: 36 additions & 0 deletions lib/mpl_toolkits/mplot3d/tests/test_art3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,42 @@
)


@pytest.mark.parametrize("container", [list, tuple])
@pytest.mark.parametrize(
"case", ["nan", "inf", "log_domain", "axlim_clip", "one_of_many"])
def test_line3d_draws_array_like_coordinates(container, case):
# set_data_3d documents its parameters as array-like and stores whatever it
# is given, so _verts3d can hold lists or tuples. Drawing must not require
# an ndarray.
#
# The masking branch that reads a shape is entered when a coordinate is
# non-finite, outside the active scale's domain, or outside the view limits
# with axlim_clip enabled, so each of those is a way in.
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
line, = ax.plot([1.], [1.], [1.],
axlim_clip=(case == "axlim_clip"))

if case == "nan":
xs, ys, zs = [np.nan], [1.], [1.]
elif case == "inf":
xs, ys, zs = [np.inf], [1.], [1.]
elif case == "log_domain":
# Finite, and invalid only because of the scale.
ax.set_xscale("log")
xs, ys, zs = [0.], [1.], [1.]
elif case == "axlim_clip":
# Finite and valid for the scale; masked for being out of view.
xs, ys, zs = [1e6], [1e6], [1e6]
else:
# A line where only one vertex is masked.
xs, ys, zs = [1., np.nan], [1., 2.], [1., 2.]

line.set_data_3d(container(xs), container(ys), container(zs))

fig.canvas.draw()


@pytest.mark.parametrize("zdir, expected", [
("x", (1, 0, 0)),
("y", (0, 1, 0)),
Expand Down
Loading