From: <he...@us...> - 2009-07-17 07:24:08
|
Revision: 7265 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7265&view=rev Author: heeres Date: 2009-07-17 07:24:06 +0000 (Fri, 17 Jul 2009) Log Message: ----------- mplot3d: add bar3d, improve z-sort, hist3d example Modified Paths: -------------- trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py Added Paths: ----------- trunk/matplotlib/examples/mplot3d/hist3d_demo.py Added: trunk/matplotlib/examples/mplot3d/hist3d_demo.py =================================================================== --- trunk/matplotlib/examples/mplot3d/hist3d_demo.py (rev 0) +++ trunk/matplotlib/examples/mplot3d/hist3d_demo.py 2009-07-17 07:24:06 UTC (rev 7265) @@ -0,0 +1,27 @@ +from mpl_toolkits.mplot3d import Axes3D +from matplotlib.collections import PolyCollection +from matplotlib.colors import colorConverter +import pylab +import random +import numpy as np + +fig = pylab.figure() +ax = Axes3D(fig) +x = np.random.rand(100) * 4 +y = np.random.rand(100) * 4 +hist, xedges, yedges = np.histogram2d(x, y, bins=4) + +elements = (len(xedges) - 1) * (len(yedges) - 1) +xpos, ypos = np.meshgrid( + [xedges[i] + 0.25 for i in range(len(xedges) - 1)], + [yedges[i] + 0.25 for i in range(len(yedges) - 1)]) +xpos = xpos.flatten() +ypos = ypos.flatten() +zpos = [0] * elements +dx = [0.5] * elements +dy = [0.5] * elements +dz = hist.flatten() +ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b') + +pylab.show() + Modified: trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py 2009-07-16 20:53:24 UTC (rev 7264) +++ trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py 2009-07-17 07:24:06 UTC (rev 7265) @@ -271,6 +271,7 @@ PolyCollection.__init__(self, verts, *args, **kwargs) self._zsort = 1 + self._sort_zpos = None def get_vector(self, segments3d): """Optimize points for projection""" @@ -287,7 +288,6 @@ ones = np.ones(len(xs)) self._vec = np.array([xs, ys, zs, ones]) self._segis = segis - self._sort_zpos = min(zs) def set_verts(self, verts, closed=True): '''Set 3D vertices.''' @@ -297,9 +297,13 @@ def set_3d_properties(self): self._zsort = 1 + self._sort_zpos = None self._facecolors3d = PolyCollection.get_facecolors(self) self._edgecolors3d = PolyCollection.get_edgecolors(self) + def set_sort_zpos(self, val): + self._sort_zpos = val + def do_3d_projection(self, renderer): ''' Perform the 3D projection for this object. @@ -315,17 +319,19 @@ # This extra fuss is to re-order face / edge colors cface = self._facecolors3d - if len(self._edgecolors3d) != len(cface): - cedge = cface - else: - cedge = self._edgecolors3d + cedge = self._edgecolors3d + if len(cface) != len(xyzlist): + cface = cface.repeat(len(xyzlist), axis=0) + if len(cedge) != len(xyzlist): + if len(cedge) == 0: + cedge = cface + cedge = cedge.repeat(len(xyzlist), axis=0) # if required sort by depth (furthest drawn first) if self._zsort: - z_segments_2d = [(min(zs), zip(xs, ys), fc, ec) for + z_segments_2d = [(np.average(zs), zip(xs, ys), fc, ec) for (xs, ys, zs), fc, ec in zip(xyzlist, cface, cedge)] - z_segments_2d.sort() - z_segments_2d.reverse() + z_segments_2d.sort(reverse=True) else: raise ValueError, "whoops" @@ -339,9 +345,12 @@ self._edgecolors2d = self._edgecolors3d # Return zorder value - zvec = np.array([[0], [0], [self._sort_zpos], [1]]) - ztrans = proj3d.proj_transform_vec(zvec, renderer.M) - return ztrans[2][0] + if self._sort_zpos is not None: + zvec = np.array([[0], [0], [self._sort_zpos], [1]]) + ztrans = proj3d.proj_transform_vec(zvec, renderer.M) + return ztrans[2][0] + else: + return np.min(tzs) def set_facecolor(self, colors): PolyCollection.set_facecolor(self, colors) Modified: trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py =================================================================== --- trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py 2009-07-16 20:53:24 UTC (rev 7264) +++ trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py 2009-07-17 07:24:06 UTC (rev 7265) @@ -625,6 +625,20 @@ return polyc + def _generate_normals(self, polygons): + ''' + Generate normals for polygons by using the first three points. + This normal of course might not make sense for polygons with + more than three points not lying in a plane. + ''' + + normals = [] + for verts in polygons: + v1 = np.array(verts[0]) - np.array(verts[1]) + v2 = np.array(verts[2]) - np.array(verts[0]) + normals.append(np.cross(v1, v2)) + return normals + def _shade_colors(self, color, normals): shade = [] for n in normals: @@ -733,6 +747,7 @@ colors2 = self._shade_colors(color, normals) polycol = art3d.Poly3DCollection(polyverts, facecolors=colors, edgecolors=colors2) + polycol.set_sort_zpos(z) self.add_collection3d(polycol) for col in colls: @@ -792,6 +807,7 @@ colls = cset.collections for z1, z2, linec in zip(levels, levels[1:], colls): art3d.poly_collection_2d_to_3d(linec, z1) + linec.set_sort_zpos(z1) self.auto_scale_xyz(X, Y, Z, had_data) return cset @@ -813,10 +829,13 @@ if type(col) is collections.PolyCollection: art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir) + col.set_sort_zpos(min(zs)) elif type(col) is collections.LineCollection: art3d.line_collection_2d_to_3d(col, zs=zs, zdir=zdir) + col.set_sort_zpos(min(zs)) elif type(col) is collections.PatchCollection: art3d.patch_collection_2d_to_3d(col, zs=zs, zdir=zdir) + col.set_sort_zpos(min(zs)) Axes.add_collection(self, col) @@ -902,6 +921,64 @@ return patches + def bar3d(self, x, y, z, dx, dy, dz, color='b'): + ''' + Generate a 3D bar, or multiple bars. + + When generating multiple bars, x, y, z have to be arrays. + dx, dy, dz can still be scalars. + ''' + + had_data = self.has_data() + + if not cbook.iterable(x): + print 'not interable' + x, y, z = [x], [y], [z] + if not cbook.iterable(dx): + dx, dy, dz = [dx], [dy], [dz] + if len(dx) == 1: + dx = dx * len(x) + dy = dy * len(x) + dz = dz * len(x) + + minx, miny, minz = 1e20, 1e20, 1e20 + maxx, maxy, maxz = -1e20, -1e20, -1e20 + + polys = [] + for xi, yi, zi, dxi, dyi, dzi in zip(x, y, z, dx, dy, dz): + minx = min(xi, minx) + maxx = max(xi + dxi, maxx) + miny = min(yi, miny) + maxy = max(yi + dyi, maxy) + minz = min(zi, minz) + maxz = max(zi + dzi, maxz) + + polys.extend([ + ((xi, yi, zi), (xi + dxi, yi, zi), + (xi + dxi, yi + dyi, zi), (xi, yi + dyi, zi)), + ((xi, yi, zi + dzi), (xi + dxi, yi, zi + dzi), + (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), + + ((xi, yi, zi), (xi + dxi, yi, zi), + (xi + dxi, yi, zi + dzi), (xi, yi, zi + dzi)), + ((xi, yi + dyi, zi), (xi + dxi, yi + dyi, zi), + (xi + dxi, yi + dyi, zi + dzi), (xi, yi + dyi, zi + dzi)), + + ((xi, yi, zi), (xi, yi + dyi, zi), + (xi, yi + dyi, zi + dzi), (xi, yi, zi + dzi)), + ((xi + dxi, yi, zi), (xi + dxi, yi + dyi, zi), + (xi + dxi, yi + dyi, zi + dzi), (xi + dxi, yi, zi + dzi)), + ]) + + color = np.array(colorConverter.to_rgba(color)) + normals = self._generate_normals(polys) + colors = self._shade_colors(color, normals) + + col = art3d.Poly3DCollection(polys, facecolor=colors) + self.add_collection(col) + + self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data) + def get_test_data(delta=0.05): ''' Return a tuple X, Y, Z with a test data set. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |