def _3d_extend_contour(self, cset, stride=5): ''' Extend a contour in 3D by creating ''' levels = cset.levels colls = cset.collections dz = (levels[1] - levels[0]) / 2 for z, linec in zip(levels, colls): topverts = art3d.paths_to_3d_segments(linec.get_paths(), z - dz) botverts = art3d.paths_to_3d_segments(linec.get_paths(), z + dz) color = linec.get_color()[0] polyverts = [] normals = [] nsteps = round(len(topverts[0]) / stride) if nsteps <= 1: if len(topverts[0]) > 1: nsteps = 2 else: continue stepsize = (len(topverts[0]) - 1) / (nsteps - 1) for i in range(int(round(nsteps)) - 1): i1 = int(round(i * stepsize)) i2 = int(round((i + 1) * stepsize)) polyverts.append([topverts[0][i1], topverts[0][i2], botverts[0][i2], botverts[0][i1]]) v1 = np.array(topverts[0][i1]) - np.array(topverts[0][i2]) v2 = np.array(topverts[0][i1]) - np.array(botverts[0][i1]) normals.append(np.cross(v1, v2)) colors = self._shade_colors(color, normals) 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: self.collections.remove(col)
def plot_surface(self, X, Y, Z, *args, **kwargs): had_data = self.has_data() rows, cols = Z.shape tX,tY,tZ = npy.transpose(X), npy.transpose(Y), npy.transpose(Z) rstride = cbook.popd(kwargs, 'rstride', 10) cstride = cbook.popd(kwargs, 'cstride', 10) # polys = [] boxes = [] for rs in npy.arange(0,rows-1,rstride): for cs in npy.arange(0,cols-1,cstride): ps = [] corners = [] for a,ta in [(X,tX),(Y,tY),(Z,tZ)]: ztop = a[rs][cs:min(cols,cs+cstride+1)] zleft = ta[min(cols-1,cs+cstride)][rs:min(rows,rs+rstride+1)] zbase = a[min(rows-1,rs+rstride)][cs:min(cols,cs+cstride+1):] zbase = zbase[::-1] zright = ta[cs][rs:min(rows,rs+rstride+1):] zright = zright[::-1] corners.append([ztop[0],ztop[-1],zbase[0],zbase[-1]]) z = npy.concatenate((ztop,zleft,zbase,zright)) ps.append(z) boxes.append(map(npy.array,zip(*corners))) polys.append(zip(*ps)) # lines = [] shade = [] for box in boxes: n = proj3d.cross(box[0]-box[1], box[0]-box[2]) n = n/proj3d.mod(n)*5 shade.append(npy.dot(n,[-1,-1,0.5])) lines.append((box[0],n+box[0])) # color = npy.array([0,0,1,1]) norm = Normalize(min(shade),max(shade)) colors = [color * (0.5+norm(v)*0.5) for v in shade] for c in colors: c[3] = 1 polyc = art3d.Poly3DCollection(polys, facecolors=colors, *args, **kwargs) polyc._zsort = 1 self.add_collection(polyc) # self.auto_scale_xyz(X,Y,Z, had_data) return polyc
def plot_surface(self, X, Y, Z, *args, **kwargs): ''' Create a surface plot. By default it will be colored in shades of a solid color, but it also supports color mapping by supplying the *cmap* argument. ============= ================================================ Argument Description ============= ================================================ *X*, *Y*, *Z* Data values as numpy.arrays *rstride* Array row stride (step size) *cstride* Array column stride (step size) *color* Color of the surface patches *cmap* A colormap for the surface patches. *facecolors* Face colors for the individual patches *norm* An instance of Normalize to map values to colors *vmin* Minimum value to map *vmax* Maximum value to map *shade* Whether to shade the facecolors ============= ================================================ Other arguments are passed on to :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection.__init__` ''' had_data = self.has_data() rows, cols = Z.shape rstride = kwargs.pop('rstride', 10) cstride = kwargs.pop('cstride', 10) if 'facecolors' in kwargs: fcolors = kwargs.pop('facecolors') else: color = np.array(colorConverter.to_rgba(kwargs.pop('color', 'b'))) fcolors = None cmap = kwargs.get('cmap', None) norm = kwargs.pop('norm', None) vmin = kwargs.pop('vmin', None) vmax = kwargs.pop('vmax', None) linewidth = kwargs.get('linewidth', None) shade = kwargs.pop('shade', cmap is None) lightsource = kwargs.pop('lightsource', None) # Shade the data if shade and cmap is not None and fcolors is not None: fcolors = self._shade_colors_lightsource(Z, cmap, lightsource) polys = [] # Only need these vectors to shade if there is no cmap if cmap is None and shade : totpts = int(np.ceil(float(rows - 1) / rstride) * np.ceil(float(cols - 1) / cstride)) v1 = np.empty((totpts, 3)) v2 = np.empty((totpts, 3)) # This indexes the vertex points which_pt = 0 #colset contains the data for coloring: either average z or the facecolor colset = [] for rs in xrange(0, rows-1, rstride): for cs in xrange(0, cols-1, cstride): ps = [] for a in (X, Y, Z) : ztop = a[rs,cs:min(cols, cs+cstride+1)] zleft = a[rs+1:min(rows, rs+rstride+1), min(cols-1, cs+cstride)] zbase = a[min(rows-1, rs+rstride), cs:min(cols, cs+cstride+1):][::-1] zright = a[rs:min(rows-1, rs+rstride):, cs][::-1] z = np.concatenate((ztop, zleft, zbase, zright)) ps.append(z) # The construction leaves the array with duplicate points, which # are removed here. ps = zip(*ps) lastp = np.array([]) ps2 = [ps[0]] + [ps[i] for i in xrange(1, len(ps)) if ps[i] != ps[i-1]] avgzsum = sum(p[2] for p in ps2) polys.append(ps2) if fcolors is not None: colset.append(fcolors[rs][cs]) else: colset.append(avgzsum / len(ps2)) # Only need vectors to shade if no cmap if cmap is None and shade: i1, i2, i3 = 0, int(len(ps2)/3), int(2*len(ps2)/3) v1[which_pt] = np.array(ps2[i1]) - np.array(ps2[i2]) v2[which_pt] = np.array(ps2[i2]) - np.array(ps2[i3]) which_pt += 1 if cmap is None and shade: normals = np.cross(v1, v2) else : normals = [] polyc = art3d.Poly3DCollection(polys, *args, **kwargs) if fcolors is not None: if shade: colset = self._shade_colors(colset, normals) polyc.set_facecolors(colset) polyc.set_edgecolors(colset) elif cmap: colset = np.array(colset) polyc.set_array(colset) if vmin is not None or vmax is not None: polyc.set_clim(vmin, vmax) if norm is not None: polyc.set_norm(norm) else: if shade: colset = self._shade_colors(color, normals) else: colset = color polyc.set_facecolors(colset) self.add_collection(polyc) self.auto_scale_xyz(X, Y, Z, had_data) return polyc
def bar3d(self, x, y, z, dx, dy, dz, color='b', zsort='average', *args, **kwargs): ''' Generate a 3D bar, or multiple bars. When generating multiple bars, x, y, z have to be arrays. dx, dy, dz can be arrays or scalars. *color* can be: - A single color value, to color all bars the same color. - An array of colors of length N bars, to color each bar independently. - An array of colors of length 6, to color the faces of the bars similarly. - An array of colors of length 6 * N bars, to color each face independently. When coloring the faces of the boxes specifically, this is the order of the coloring: 1. -Z (bottom of box) 2. +Z (top of box) 3. -Y 4. +Y 5. -X 6. +X Keyword arguments are passed onto :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` ''' had_data = self.has_data() if not cbook.iterable(x): x = [x] if not cbook.iterable(y): y = [y] if not cbook.iterable(z): z = [z] if not cbook.iterable(dx): dx = [dx] if not cbook.iterable(dy): dy = [dy] if not cbook.iterable(dz): dz = [dz] if len(dx) == 1: dx = dx * len(x) if len(dy) == 1: dy = dy * len(y) if len(dz) == 1: dz = dz * len(z) if len(x) != len(y) or len(x) != len(z): warnings.warn('x, y, and z must be the same length.') 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)), ]) facecolors = [] if color is None: # no color specified facecolors = [None] * len(x) elif len(color) == len(x): # bar colors specified, need to expand to number of faces for c in color: facecolors.extend([c] * 6) else: # a single color specified, or face colors specified explicitly facecolors = list(colorConverter.to_rgba_array(color)) if len(facecolors) < len(x): facecolors *= (6 * len(x)) normals = self._generate_normals(polys) sfacecolors = self._shade_colors(facecolors, normals) col = art3d.Poly3DCollection(polys, zsort=zsort, facecolor=sfacecolors, *args, **kwargs) self.add_collection(col) self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data)
def plot_surface(self, X, Y, Z, *args, **kwargs): ''' Create a surface plot. By default it will be colored in shades of a solid color, but it also supports color mapping by supplying the *cmap* argument. ========== ================================================ Argument Description ========== ================================================ *X*, *Y*, Data values as numpy.arrays *Z* *rstride* Array row stride (step size) *cstride* Array column stride (step size) *color* Color of the surface patches *cmap* A colormap for the surface patches. ========== ================================================ ''' had_data = self.has_data() rows, cols = Z.shape tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z) rstride = kwargs.pop('rstride', 10) cstride = kwargs.pop('cstride', 10) color = kwargs.pop('color', 'b') color = np.array(colorConverter.to_rgba(color)) cmap = kwargs.get('cmap', None) polys = [] normals = [] avgz = [] for rs in np.arange(0, rows - 1, rstride): for cs in np.arange(0, cols - 1, cstride): ps = [] corners = [] for a, ta in [(X, tX), (Y, tY), (Z, tZ)]: ztop = a[rs][cs:min(cols, cs + cstride + 1)] zleft = ta[min(cols - 1, cs + cstride)][rs:min(rows, rs + rstride + 1)] zbase = a[min(rows - 1, rs + rstride)][cs:min(cols, cs + cstride + 1):] zbase = zbase[::-1] zright = ta[cs][rs:min(rows, rs + rstride + 1):] zright = zright[::-1] corners.append([ztop[0], ztop[-1], zbase[0], zbase[-1]]) z = np.concatenate((ztop, zleft, zbase, zright)) ps.append(z) # The construction leaves the array with duplicate points, which # are removed here. ps = zip(*ps) lastp = np.array([]) ps2 = [] avgzsum = 0.0 for p in ps: if p != lastp: ps2.append(p) lastp = p avgzsum += p[2] polys.append(ps2) avgz.append(avgzsum / len(ps2)) v1 = np.array(ps2[0]) - np.array(ps2[1]) v2 = np.array(ps2[2]) - np.array(ps2[0]) normals.append(np.cross(v1, v2)) polyc = art3d.Poly3DCollection(polys, *args, **kwargs) if cmap is not None: polyc.set_array(np.array(avgz)) polyc.set_linewidth(0) else: colors = self._shade_colors(color, normals) polyc.set_facecolors(colors) self.add_collection(polyc) self.auto_scale_xyz(X, Y, Z, had_data) return polyc
def plot_surface(self, X, Y, Z, *args, **kwargs): ''' Create a surface plot. By default it will be colored in shades of a solid color, but it also supports color mapping by supplying the *cmap* argument. ============= ================================================ Argument Description ============= ================================================ *X*, *Y*, *Z* Data values as numpy.arrays *rstride* Array row stride (step size) *cstride* Array column stride (step size) *color* Color of the surface patches *cmap* A colormap for the surface patches. *facecolors* Face colors for the individual patches *norm* An instance of Normalize to map values to colors *vmin* Minimum value to map *vmax* Maximum value to map *shade* Whether to shade the facecolors ============= ================================================ Other arguments are passed on to :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection.__init__` ''' had_data = self.has_data() rows, cols = Z.shape tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z) rstride = kwargs.pop('rstride', 10) cstride = kwargs.pop('cstride', 10) if 'facecolors' in kwargs: fcolors = kwargs.pop('facecolors') else: color = np.array(colorConverter.to_rgba(kwargs.pop('color', 'b'))) fcolors = None cmap = kwargs.get('cmap', None) norm = kwargs.pop('norm', None) vmin = kwargs.pop('vmin', None) vmax = kwargs.pop('vmax', None) linewidth = kwargs.get('linewidth', None) shade = kwargs.pop('shade', cmap is None) lightsource = kwargs.pop('lightsource', None) # Shade the data if shade and cmap is not None and fcolors is not None: fcolors = self._shade_colors_lightsource(Z, cmap, lightsource) polys = [] normals = [] #colset contains the data for coloring: either average z or the facecolor colset = [] for rs in np.arange(0, rows - 1, rstride): for cs in np.arange(0, cols - 1, cstride): ps = [] corners = [] for a, ta in [(X, tX), (Y, tY), (Z, tZ)]: ztop = a[rs][cs:min(cols, cs + cstride + 1)] zleft = ta[min(cols - 1, cs + cstride)][rs:min(rows, rs + rstride + 1)] zbase = a[min(rows - 1, rs + rstride)][cs:min(cols, cs + cstride + 1):] zbase = zbase[::-1] zright = ta[cs][rs:min(rows, rs + rstride + 1):] zright = zright[::-1] corners.append([ztop[0], ztop[-1], zbase[0], zbase[-1]]) z = np.concatenate((ztop, zleft, zbase, zright)) ps.append(z) # The construction leaves the array with duplicate points, which # are removed here. ps = zip(*ps) lastp = np.array([]) ps2 = [] avgzsum = 0.0 for p in ps: if p != lastp: ps2.append(p) lastp = p avgzsum += p[2] polys.append(ps2) if fcolors is not None: colset.append(fcolors[rs][cs]) else: colset.append(avgzsum / len(ps2)) # Only need vectors to shade if no cmap if cmap is None and shade: v1 = np.array(ps2[0]) - np.array(ps2[1]) v2 = np.array(ps2[2]) - np.array(ps2[0]) normals.append(np.cross(v1, v2)) polyc = art3d.Poly3DCollection(polys, *args, **kwargs) if fcolors is not None: if shade: colset = self._shade_colors(colset, normals) polyc.set_facecolors(colset) polyc.set_edgecolors(colset) elif cmap: colset = np.array(colset) polyc.set_array(colset) if vmin is not None or vmax is not None: polyc.set_clim(vmin, vmax) if norm is not None: polyc.set_norm(norm) else: if shade: colset = self._shade_colors(color, normals) else: colset = color polyc.set_facecolors(colset) self.add_collection(polyc) self.auto_scale_xyz(X, Y, Z, had_data) return polyc