diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 76bdf35b0657..8b88134e220b 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -578,13 +578,28 @@ def set_zsort(self, zsort): def get_vector(self, segments3d): """Optimize points for projection.""" if len(segments3d): - xs, ys, zs = np.row_stack(segments3d).T + # row_stack would split and re-concatenate all rows, and so it's + # much faster to reshape if the data is already in the right format + if isinstance(segments3d, np.ndarray): + segments3d_t = segments3d.reshape(-1, segments3d.shape[-1]).T + else: + segments3d_t = np.row_stack(segments3d).T + ones = np.broadcast_to(np.ones((1,), dtype=segments3d_t.dtype), + shape=(1, segments3d_t.shape[-1],)) + self._vec = np.concatenate((segments3d_t, ones), axis=0) else: # row_stack can't stack zero arrays. - xs, ys, zs = [], [], [] - ones = np.ones(len(xs)) - self._vec = np.array([xs, ys, zs, ones]) - - indices = [0, *np.cumsum([len(segment) for segment in segments3d])] + self._vec = np.ndarray(shape=(0, 4)) + + # range is much faster than np.cumsum with a list argument, so we + # use it whenever the faces have a constant number of vertices. + if isinstance(segments3d, np.ndarray): + face_vertices = segments3d.shape[1] + segment_ends = range(face_vertices, + face_vertices * len(segments3d) + 1, + face_vertices) + else: + segment_ends = np.cumsum([len(segment) for segment in segments3d]) + indices = [0, *segment_ends] self._segslices = [*map(slice, indices[:-1], indices[1:])] def set_verts(self, verts, closed=True):