8000 Optimize 3D display by AlexandreAbraham · Pull Request #6085 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Optimize 3D display #6085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Prev Previous commit
Next Next commit
Vectorize output of proj_transform_vec
  • Loading branch information
AlexandreAbraham committed Jun 8, 2016
commit 5239e1ae407f59b575fe10dcf61eea968ad00134
48 changes: 25 additions & 23 deletions lib/mpl_toolkits/mplot3d/art3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ def set_3d_properties(self, zs=0, zdir='z'):

def draw(self, renderer):
xs3d, ys3d, zs3d = self._verts3d
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
self.set_data(xs, ys)
xyz = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
self.set_data(xyz[0], xyz[1])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for me, set_data(xyz[0], xyz[1]) looks uglier then set_data(xs, ys).

lines.Line2D.draw(self, renderer)
self.stale = False

Expand Down Expand Up @@ -271,11 +271,11 @@ def get_facecolor(self):
def do_3d_projection(self, renderer):
s = self._segment3d
xs, ys, zs = list(zip(*s))
vxs, vys,vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
self._path2d = mpath.Path(list(zip(vxs, vys)))
vxyzis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
self._path2d = mpath.Path(vxyzis[0:2].T)
# FIXME: coloring
self._facecolor2d = self._facecolor3d
return min(vzs)
return min(vxyzis[2])

def draw(self, renderer):
Patch.draw(self, renderer)
Expand All @@ -299,11 +299,11 @@ def set_3d_properties(self, path, zs=0, zdir='z'):
def do_3d_projection(self, renderer):
s = self._segment3d
xs, ys, zs = list(zip(*s))
vxs, vys,vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
self._path2d = mpath.Path(list(zip(vxs, vys)), self._code3d)
vxyzis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
self._path2d = mpath.Path(vxyzis[0:2].T, self._code3d)
# FIXME: coloring
self._facecolor2d = self._facecolor3d
return min(vzs)
return min(vxyzis[2])

def get_patch_verts(patch):
"""Return a list of vertices for the path of a patch."""
Expand Down Expand Up @@ -379,21 +379,21 @@ def set_3d_properties(self, zs, zdir):

def do_3d_projection(self, renderer):
xs, ys, zs = self._offsets3d
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
vxyzis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)

fcs = (zalpha(self._facecolor3d, vzs) if self._depthshade else
fcs = (zalpha(self._facecolor3d, vxyzis[2]) if self._depthshade else
self._facecolor3d)
fcs = mcolors.to_rgba_array(fcs, self._alpha)
self.set_facecolors(fcs)

ecs = (zalpha(self._edgecolor3d, vzs) if self._depthshade else
ecs = (zalpha(self._edgecolor3d, vxyzis[2]) if self._depthshade else
self._edgecolor3d)
ecs = mcolors.to_rgba_array(ecs, self._alpha)
self.set_edgecolors(ecs)
PatchCollection.set_offsets(self, list(zip(vxs, vys)))
PatchCollection.set_offsets(self, vxyzis[0:2].T)

if vzs.size > 0:
return min(vzs)
if len(vxyzis) > 0:
return min(vxyzis[2])
else:
return np.nan

Expand Down Expand Up @@ -447,22 +447,22 @@ def set_3d_properties(self, zs, zdir):

def do_3d_projection(self, renderer):
xs, ys, zs = self._offsets3d
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)
vxyzis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M)

fcs = (zalpha(self._facecolor3d, vzs) if self._depthshade else
fcs = (zalpha(self._facecolor3d, vxyzis[2]) if self._depthshade else
self._facecolor3d)
fcs = mcolors.to_rgba_array(fcs, self._alpha)
self.set_facecolors(fcs)

ecs = (zalpha(self._edgecolor3d, vzs) if self._depthshade else
ecs = (zalpha(self._edgecolor3d, vxyzis[2]) if self._depthshade else
self._edgecolor3d)
ecs = mcolors.to_rgba_array(ecs, self._alpha)
self.set_edgecolors(ecs)
PathCollection.set_offsets(self, list(zip(vxs, vys)))
PathCollection.set_offsets(self, vxyzis[0:2].T)

if vzs.size > 0 :
return min(vzs)
else :
if len(vxyzis) > 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition should be len(vxyzis[2]) > 0. You'd better to make vzs = vxyzis[2] (or _, _, vzs, _ = vxyzis = proj3d....) and then use vzs here and above.

return min(vxyzis[2])
else:
return np.nan


Expand Down Expand Up @@ -545,7 +545,10 @@ def set_zsort(self, zsort):

def get_vector(self, segments3d):
"""Optimize points for projection"""
# Segments 3d are given in shape (n_segments, 3, 3)
# Flatten them
xys = segments3d.reshape((-1, 3)).T
# Add a fourth dimension with only ones
ones = np.ones(xys.shape[1])
self._vec = np.vstack([xys, ones])

Expand Down Expand Up @@ -589,8 +592,7 @@ def do_3d_projection(self, renderer):
self.update_scalarmappable()
self._facecolors3d = self._facecolors

# XXX proj_transform_vec can work with arrays only
xys = np.array(proj3d.proj_transform_vec(self._vec, renderer.M))
xys = proj3d.proj_transform_vec(self._vec, renderer.M)
xyzlist = np.transpose(xys.T.reshape((-1, 3, 3)), axes=[0, 2, 1])

# This extra fuss is to re-order face / edge colors
Expand Down
20 changes: 11 additions & 9 deletions lib/mpl_toolkits/mplot3d/proj3d.py
8000
Original file line number Diff line number Diff line change
Expand Up @@ -156,20 +156,22 @@ def persp_transformation(zfront, zback):

def proj_transform_vec(vec, M):
vecw = np.dot(M, vec)
w = vecw[3]
# clip here..
txs, tys, tzs = vecw[0]/w, vecw[1]/w, vecw[2]/w
return txs, tys, tzs
vecw /= vecw[3]
return vecw[0:3]

def proj_transform_vec_clip(vec, M):
vecw = np.dot(M, vec)
w = vecw[3]
# Determine clipping before rescaling
tis = np.logical_and(vecw[0] >= 0, vecw[0] <= 1,
vecw[1] >= 0, vecw[1] <= 1)
# clip here..
txs, tys, tzs = vecw[0]/w, vecw[1]/w, vecw[2]/w
tis = (vecw[0] >= 0) * (vecw[0] <= 1) * (vecw[1] >= 0) * (vecw[1] <= 1)
# Can anybody comment on this piece of code? I don't understand it...
if np.sometrue(tis):
tis = vecw[1] < 1
return txs, tys, tzs, tis
tis = vecw[1] < 1
vecw /= vecw[3]
# Integrating tis in the numpy array for optimization purposes
vecw[3, :] = tis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get rid of this colon - it makes the function fail on 1d inputs

return vecw

def inv_transform(xs, ys, zs, M):
iM = linalg.inv(M)
Expand Down
0