Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fcfe8b1

Browse filesBrowse files
committed
Convert existing mplot3d functions to use transforms
1 parent eb7676c commit fcfe8b1
Copy full SHA for fcfe8b1

File tree

3 files changed

+76
-98
lines changed
Filter options

3 files changed

+76
-98
lines changed

‎lib/mpl_toolkits/mplot3d/art3d.py

Copy file name to clipboardExpand all lines: lib/mpl_toolkits/mplot3d/art3d.py
+53-69Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
Collection, LineCollection, PolyCollection, PatchCollection, PathCollection)
2121
from matplotlib.colors import Normalize
2222
from matplotlib.patches import Patch
23-
from . import proj3d
2423

2524

2625
def _norm_angle(a):
@@ -148,12 +147,11 @@ def set_3d_properties(self, z=0, zdir='z'):
148147
@artist.allow_rasterization
149148
def draw(self, renderer):
150149
position3d = np.array((self._x, self._y, self._z))
151-
proj = proj3d._proj_trans_points(
152-
[position3d, position3d + self._dir_vec], self.axes.M)
153-
dx = proj[0][1] - proj[0][0]
154-
dy = proj[1][1] - proj[1][0]
150+
proj = self.axes.M.transform([position3d, position3d + self._dir_vec])
151+
dx = proj[1][0] - proj[0][0]
152+
dy = proj[1][1] - proj[0][1]
155153
angle = math.degrees(math.atan2(dy, dx))
156-
with cbook._setattr_cm(self, _x=proj[0][0], _y=proj[1][0],
154+
with cbook._setattr_cm(self, _x=proj[0][0], _y=proj[0][1],
157155
_rotation=_norm_text_angle(angle)):
158156
mtext.Text.draw(self, renderer)
159157
self.stale = False
@@ -267,8 +265,8 @@ def get_data_3d(self):
267265
@artist.allow_rasterization
268266
def draw(self, renderer):
269267
xs3d, ys3d, zs3d = self._verts3d
270-
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
271-
self.set_data(xs, ys)
268+
points = self.axes.M.transform(np.column_stack((xs3d, ys3d, zs3d)))
269+
self.set_data(points[:, 0], points[:, 1])
272270
super().draw(renderer)
273271
self.stale = False
274272

@@ -349,11 +347,11 @@ class Collection3D(Collection):
349347

350348
def do_3d_projection(self):
351349
"""Project the points according to renderer matrix."""
352-
xyzs_list = [proj3d.proj_transform(*vs.T, self.axes.M)
353-
for vs, _ in self._3dverts_codes]
354-
self._paths = [mpath.Path(np.column_stack([xs, ys]), cs)
355-
for (xs, ys, _), (_, cs) in zip(xyzs_list, self._3dverts_codes)]
356-
zs = np.concatenate([zs for _, _, zs in xyzs_list])
350+
path_vertices = [self.axes.M.transform(vs) for vs, _ in self._3dverts_codes]
351+
self._paths = [mpath.Path(vertices[:, :2], codes)
352+
for (vertices, (_, codes))
353+
in zip(path_vertices, self._3dverts_codes)]
354+
zs = np.concatenate(path_vertices)[:, 2]
357355
return zs.min() if len(zs) else 1e9
358356

359357

@@ -390,15 +388,14 @@ def do_3d_projection(self):
390388
"""
391389
Project the points according to renderer matrix.
392390
"""
393-
xyslist = [proj3d._proj_trans_points(points, self.axes.M)
394-
for points in self._segments3d]
395-
segments_2d = [np.column_stack([xs, ys]) for xs, ys, zs in xyslist]
391+
segments_3d = [self.axes.M.transform(segment) for segment in self._segments3d]
392+
segments_2d = [segment[:, :2] for segment in segments_3d]
396393
LineCollection.set_segments(self, segments_2d)
397394

398395
# FIXME
399396
minz = 1e9
400-
for xs, ys, zs in xyslist:
401-
minz = min(minz, min(zs))
397+
for segment in segments_3d:
398+
minz = min(minz, segment[0][2], segment[1][2])
402399
return minz
403400

404401

@@ -456,12 +453,10 @@ def get_path(self):
456453
return self._path2d
457454

458455
def do_3d_projection(self):
459-
s = self._segment3d
460-
xs, ys, zs = zip(*s)
461-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
462-
self.axes.M)
463-
self._path2d = mpath.Path(np.column_stack([vxs, vys]))
464-
return min(vzs)
456+
segments = self.axes.M.transform(self._segment3d)
457+
self._path2d = mpath.Path(segments[:, :2])
458+
459+
return min(segments[:, 2])
465460

466461

467462
class PathPatch3D(Patch3D):
@@ -503,12 +498,10 @@ def set_3d_properties(self, path, zs=0, zdir='z'):
503498
self._code3d = path.codes
504499

505500
def do_3d_projection(self):
506-
s = self._segment3d
507-
xs, ys, zs = zip(*s)
508-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
509-
self.axes.M)
510-
self._path2d = mpath.Path(np.column_stack([vxs, vys]), self._code3d)
511-
return min(vzs)
501+
segments = self.axes.M.transform(self._segment3d)
502+
self._path2d = mpath.Path(segments[:, :2], self._code3d)
503+
504+
return min(segments[:, 2])
512505

513506

514507
def _get_patch_verts(patch):
@@ -610,14 +603,13 @@ def set_3d_properties(self, zs, zdir):
610603
self.stale = True
611604

612605
def do_3d_projection(self):
613-
xs, ys, zs = self._offsets3d
614-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
615-
self.axes.M)
616-
self._vzs = vzs
617-
super().set_offsets(np.column_stack([vxs, vys]))
606+
points = self.axes.M.transform(np.column_stack(self._offsets3d))
607+
super().set_offsets(points[:, :2])
618608

619-
if vzs.size > 0:
620-
return min(vzs)
609+
self._vzs = points[:, 2]
610+
611+
if self._vzs.size > 0:
612+
return min(self._vzs)
621613
else:
622614
return np.nan
623615

@@ -751,37 +743,31 @@ def set_depthshade(self, depthshade):
751743
self.stale = True
752744

753745
def do_3d_projection(self):
754-
xs, ys, zs = self._offsets3d
755-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
756-
self.axes.M)
757746
# Sort the points based on z coordinates
758747
# Performance optimization: Create a sorted index array and reorder
759748
# points and point properties according to the index array
760-
z_markers_idx = self._z_markers_idx = np.argsort(vzs)[::-1]
761-
self._vzs = vzs
749+
points = self.axes.M.transform(np.column_stack(self._offsets3d))
750+
z_markers_idx = self._z_markers_idx = np.argsort(points[:, 2])[::-1]
751+
self._vzs = points[:, 2]
762752

763753
# we have to special case the sizes because of code in collections.py
764754
# as the draw method does
765755
# self.set_sizes(self._sizes, self.figure.dpi)
766756
# so we cannot rely on doing the sorting on the way out via get_*
767-
768757
if len(self._sizes3d) > 1:
769758
self._sizes = self._sizes3d[z_markers_idx]
770759

771760
if len(self._linewidths3d) > 1:
772761
self._linewidths = self._linewidths3d[z_markers_idx]
773762

774-
PathCollection.set_offsets(self, np.column_stack((vxs, vys)))
763+
PathCollection.set_offsets(self, points[:, :2])
775764

776765
# Re-order items
777-
vzs = vzs[z_markers_idx]
778-
vxs = vxs[z_markers_idx]
779-
vys = vys[z_markers_idx]
766+
points = points[z_markers_idx]
780767

781768
# Store ordered offset for drawing purpose
782-
self._offset_zordered = np.column_stack((vxs, vys))
783-
784-
return np.min(vzs) if vzs.size else np.nan
769+
self._offset_zordered = points[:, :2]
770+
return np.min(self._vzs) if self._vzs.size else np.nan
785771

786772
@contextmanager
787773
def _use_zordered_offset(self):
@@ -954,8 +940,7 @@ def get_vector(self, segments3d):
954940
xs, ys, zs = np.vstack(segments3d).T
955941
else: # vstack can't stack zero arrays.
956942
xs, ys, zs = [], [], []
957-
ones = np.ones(len(xs))
958-
self._vec = np.array([xs, ys, zs, ones])
943+
self._vec = np.array([xs, ys, zs])
959944

960945
indices = [0, *np.cumsum([len(segment) for segment in segments3d])]
961946
self._segslices = [*map(slice, indices[:-1], indices[1:])]
@@ -1020,27 +1005,28 @@ def do_3d_projection(self):
10201005
self._facecolor3d = self._facecolors
10211006
if self._edge_is_mapped:
10221007
self._edgecolor3d = self._edgecolors
1023-
txs, tys, tzs = proj3d._proj_transform_vec(self._vec, self.axes.M)
1024-
xyzlist = [(txs[sl], tys[sl], tzs[sl]) for sl in self._segslices]
1008+
1009+
verts = self.axes.M.transform(np.column_stack(self._vec))
1010+
verts_slices = [verts[sl] for sl in self._segslices]
10251011

10261012
# This extra fuss is to re-order face / edge colors
10271013
cface = self._facecolor3d
10281014
cedge = self._edgecolor3d
1029-
if len(cface) != len(xyzlist):
1030-
cface = cface.repeat(len(xyzlist), axis=0)
1031-
if len(cedge) != len(xyzlist):
1015+
1016+
if len(cface) != len(verts_slices):
1017+
cface = cface.repeat(len(verts_slices), axis=0)
1018+
if len(cedge) != len(verts_slices):
10321019
if len(cedge) == 0:
10331020
cedge = cface
10341021
else:
1035-
cedge = cedge.repeat(len(xyzlist), axis=0)
1022+
cedge = cedge.repeat(len(verts_slices), axis=0)
10361023

1037-
if xyzlist:
1038-
# sort by depth (furthest drawn first)
1024+
if verts_slices:
10391025
z_segments_2d = sorted(
1040-
((self._zsortfunc(zs), np.column_stack([xs, ys]), fc, ec, idx)
1041-
for idx, ((xs, ys, zs), fc, ec)
1042-
in enumerate(zip(xyzlist, cface, cedge))),
1043-
key=lambda x: x[0], reverse=True)
1026+
((self._zsortfunc(verts[:, 2]), verts[:, :2], fc, ec, idx)
1027+
for idx, (verts, fc, ec)
1028+
in enumerate(zip(verts_slices, cface, cedge))),
1029+
key=lambda x: x[0], reverse=True)
10441030

10451031
_, segments_2d, self._facecolors2d, self._edgecolors2d, idxs = \
10461032
zip(*z_segments_2d)
@@ -1061,14 +1047,12 @@ def do_3d_projection(self):
10611047

10621048
# Return zorder value
10631049
if self._sort_zpos is not None:
1064-
zvec = np.array([[0], [0], [self._sort_zpos], [1]])
1065-
ztrans = proj3d._proj_transform_vec(zvec, self.axes.M)
1066-
return ztrans[2][0]
1067-
elif tzs.size > 0:
1050+
return self.axes.M.transform([0, 0, self._sort_zpos])[2]
1051+
elif len(verts) > 0:
10681052
# FIXME: Some results still don't look quite right.
10691053
# In particular, examine contourf3d_demo2.py
10701054
# with az = -54 and elev = -45.
1071-
return np.min(tzs)
1055+
return np.min(verts[:, 2])
10721056
else:
10731057
return np.nan
10741058

‎lib/mpl_toolkits/mplot3d/axes3d.py

Copy file name to clipboardExpand all lines: lib/mpl_toolkits/mplot3d/axes3d.py
+14-20Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from . import art3d
3636
from . import proj3d
3737
from . import axis3d
38+
from . import transform3d
3839

3940

4041
@_docstring.interpd
@@ -158,8 +159,8 @@ def __init__(
158159
super().set_axis_off()
159160
# Enable drawing of axes by Axes3D class
160161
self.set_axis_on()
161-
self.M = None
162-
self.invM = None
162+
self.M = mtransforms.IdentityTransform(dims=3)
163+
self.invM = mtransforms.IdentityTransform(dims=3)
163164

164165
self._view_margin = 1/48 # default value to match mpl3.8
165166
self.autoscale_view()
@@ -236,7 +237,7 @@ def _transformed_cube(self, vals):
236237
(maxx, miny, maxz),
237238
(maxx, maxy, maxz),
238239
(minx, maxy, maxz)]
239-
return proj3d._proj_points(xyzs, self.M)
240+
return self.M.transform(xyzs)
240241

241242
def set_aspect(self, aspect, adjustable=None, anchor=None, share=False):
242243
"""
@@ -423,7 +424,7 @@ def draw(self, renderer):
423424

424425
# add the projection matrix to the renderer
425426
self.M = self.get_proj()
426-
self.invM = np.linalg.inv(self.M)
427+
self.invM = self.M.inverted()
427428

428429
collections_and_patches = (
429430
artist for artist in self._children
@@ -1200,12 +1201,8 @@ def get_proj(self):
12001201

12011202
# Transform to uniform world coordinates 0-1, 0-1, 0-1
12021203
box_aspect = self._roll_to_vertical(self._box_aspect)
1203-
worldM = proj3d.world_transformation(
1204-
*self.get_xlim3d(),
1205-
*self.get_ylim3d(),
1206-
*self.get_zlim3d(),
1207-
pb_aspect=box_aspect,
1208-
)
1204+
worldM = transform3d.WorldTransform(*self.get_xlim3d(), *self.get_ylim3d(),
1205+
*self.get_zlim3d(), pb_aspect=box_aspect)
12091206

12101207
# Look into the middle of the world coordinates:
12111208
R = 0.5 * box_aspect
@@ -1238,21 +1235,18 @@ def get_proj(self):
12381235
# Generate the view and projection transformation matrices
12391236
if self._focal_length == np.inf:
12401237
# Orthographic projection
1241-
viewM = proj3d._view_transformation_uvw(u, v, w, eye)
1242-
projM = proj3d._ortho_transformation(-self._dist, self._dist)
1238+
viewM = transform3d.ViewTransform(u, v, w, eye)
1239+
projM = transform3d.OrthographicTransform(-self._dist, self._dist)
12431240
else:
12441241
# Perspective projection
12451242
# Scale the eye dist to compensate for the focal length zoom effect
12461243
eye_focal = R + self._dist * ps * self._focal_length
1247-
viewM = proj3d._view_transformation_uvw(u, v, w, eye_focal)
1248-
projM = proj3d._persp_transformation(-self._dist,
1249-
self._dist,
1250-
self._focal_length)
1244+
viewM = transform3d.ViewTransform(u, v, w, eye_focal)
1245+
projM = transform3d.PerspectiveTransform(-self._dist, self._dist,
1246+
self._focal_length)
12511247

12521248
# Combine all the transformation matrices to get the final projection
1253-
M0 = np.dot(viewM, worldM)
1254-
M = np.dot(projM, M0)
1255-
return M
1249+
return worldM + viewM + projM
12561250

12571251
def mouse_init(self, rotate_btn=1, pan_btn=2, zoom_btn=3):
12581252
"""
@@ -1459,7 +1453,7 @@ def _calc_coord(self, xv, yv, renderer=None):
14591453
zv = -1 / self._focal_length
14601454

14611455
# Convert point on view plane to data coordinates
1462-
p1 = np.array(proj3d.inv_transform(xv, yv, zv, self.invM)).ravel()
1456+
p1 = self.invM.transform([xv, yv, zv])
14631457

14641458
# Get the vector from the camera to the point on the view plane
14651459
vec = self._get_camera_loc() - p1

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.