From: <ef...@us...> - 2009-08-04 07:01:54
|
Revision: 7341 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7341&view=rev Author: efiring Date: 2009-08-04 07:01:43 +0000 (Tue, 04 Aug 2009) Log Message: ----------- contourf uses complex paths instead of simple paths with cuts Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/contour.py trunk/matplotlib/src/cntr.c Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-08-04 06:52:24 UTC (rev 7340) +++ trunk/matplotlib/CHANGELOG 2009-08-04 07:01:43 UTC (rev 7341) @@ -1,3 +1,6 @@ +2009-08-03 Add PathCollection; modify contourf to use complex + paths instead of simple paths with cuts. - EF + 2009-08-03 Fixed boilerplate.py so it doesn't break the ReST docs. - JKS ====================================================================== Modified: trunk/matplotlib/lib/matplotlib/contour.py =================================================================== --- trunk/matplotlib/lib/matplotlib/contour.py 2009-08-04 06:52:24 UTC (rev 7340) +++ trunk/matplotlib/lib/matplotlib/contour.py 2009-08-04 07:01:43 UTC (rev 7341) @@ -8,7 +8,7 @@ import numpy as np from numpy import ma import matplotlib._cntr as _cntr -import matplotlib.path as path +import matplotlib.path as mpath import matplotlib.ticker as ticker import matplotlib.cm as cm import matplotlib.colors as colors @@ -499,7 +499,7 @@ if inline: for n in new: # Add path if not empty or single point - if len(n)>1: additions.append( path.Path(n) ) + if len(n)>1: additions.append( mpath.Path(n) ) else: # If not adding label, keep old path additions.append(linepath) @@ -579,6 +579,8 @@ self.collections = cbook.silent_list('collections.PolyCollection') else: self.collections = cbook.silent_list('collections.LineCollection') + self.segs = [] + self.kinds = [] # label lists must be initialized here self.labelTexts = [] self.labelCValues = [] @@ -601,13 +603,21 @@ for level, level_upper in zip(lowers, uppers): nlist = C.trace(level, level_upper, points = 0, nchunk = self.nchunk) - col = collections.PolyCollection(nlist, + nseg = len(nlist)//2 + segs = nlist[:nseg] + kinds = nlist[nseg:] + + + paths = self._make_paths(segs, kinds) + + col = collections.PathCollection(paths, antialiaseds = (self.antialiased,), edgecolors= 'none', alpha=self.alpha) self.ax.add_collection(col) self.collections.append(col) - + self.segs.append(segs) + self.kinds.append(kinds) else: tlinewidths = self._process_linewidths() self.tlinewidths = tlinewidths @@ -615,7 +625,10 @@ C = _cntr.Cntr(x, y, z.filled(), _mask) for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles): nlist = C.trace(level, points = 0) - col = collections.LineCollection(nlist, + nseg = len(nlist)//2 + segs = nlist[:nseg] + kinds = nlist[nseg:] + col = collections.LineCollection(segs, linewidths = width, linestyle = lstyle, alpha=self.alpha) @@ -623,6 +636,8 @@ col.set_label('_nolegend_') self.ax.add_collection(col, False) self.collections.append(col) + self.segs.append(segs) + self.kinds.append(kinds) self.changed() # set the colors x0 = ma.minimum(x) x1 = ma.maximum(x) @@ -631,6 +646,17 @@ self.ax.update_datalim([(x0,y0), (x1,y1)]) self.ax.autoscale_view() + @staticmethod + def _make_paths(segs, kinds): + paths = [] + for seg, kind in zip(segs, kinds): + codes = np.zeros(kind.shape, dtype=mpath.Path.code_type) + codes.fill(mpath.Path.LINETO) + codes[0] = mpath.Path.MOVETO + codes[kinds >= _cntr._slitkind] = mpath.Path.MOVETO + paths.append(mpath.Path(seg, codes)) + return paths + def changed(self): tcolors = [ (tuple(rgba),) for rgba in self.to_rgba(self.cvalues, alpha=self.alpha)] Modified: trunk/matplotlib/src/cntr.c =================================================================== --- trunk/matplotlib/src/cntr.c 2009-08-04 06:52:24 UTC (rev 7340) +++ trunk/matplotlib/src/cntr.c 2009-08-04 07:01:43 UTC (rev 7341) @@ -199,6 +199,7 @@ /* making the actual marks requires a bunch of other stuff */ const double *x, *y, *z; /* mesh coordinates and function values */ double *xcp, *ycp; /* output contour points */ + short *kcp; /* kind of contour point */ }; void print_Csite(Csite *Csite) @@ -268,6 +269,9 @@ #define START_MARK(left) \ ((left)>0?((left)>1?J1_START:I1_START):((left)<-1?J0_START:I0_START)) +enum {kind_zone, kind_edge1, kind_edge2, + kind_slit_up, kind_slit_down, kind_start_slit=16} point_kinds; + /* ------------------------------------------------------------------------ */ /* these actually mark points */ @@ -317,6 +321,7 @@ double zlevel = pass2 ? site->zlevel[level] : 0.0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; + short *kcp = pass2 ? site->kcp : 0; int z0, z1, z2, z3; int keep_left = 0; /* flag to try to minimize curvature in saddles */ @@ -338,6 +343,7 @@ double zcp = (zlevel - z[p0]) / (z[p1] - z[p0]); xcp[n] = zcp * (x[p1] - x[p0]) + x[p0]; ycp[n] = zcp * (y[p1] - y[p0]) + y[p0]; + kcp[n] = kind_zone; } if (!done && !jedge) { @@ -487,7 +493,15 @@ site->edge = edge; site->n = n; site->left = left; - return done > 4 ? slit_cutter (site, done - 5, pass2) : done; + if (done <= 4) + { + return done; + } + if (pass2 && n > 0) + { + kcp[n-1] += kind_start_slit; + } + return slit_cutter (site, done - 5, pass2); } /* edge_walker assumes that the current edge is being drawn CCW @@ -513,11 +527,13 @@ long left0 = site->left0; int level0 = site->level0 == 2; int marked; + int n_kind = 0; const double *x = pass2 ? site->x : 0; const double *y = pass2 ? site->y : 0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; + short *kcp = pass2 ? site->kcp : 0; int z0, z1, heads_up = 0; @@ -528,6 +544,7 @@ z0 = data[p0] & Z_VALUE; z1 = data[p1] & Z_VALUE; marked = 0; + n_kind = 0; if (z0 == 1) { /* mark current boundary point */ @@ -535,6 +552,8 @@ { xcp[n] = x[p0]; ycp[n] = y[p0]; + kcp[n] = kind_edge1; + n_kind = n; } marked = 1; } @@ -549,6 +568,8 @@ zcp = (zcp - site->z[p0]) / (site->z[p1] - site->z[p0]); xcp[n] = zcp * (x[p1] - x[p0]) + x[p0]; ycp[n] = zcp * (y[p1] - y[p0]) + y[p0]; + kcp[n] = kind_edge2; + n_kind = n; } marked = 1; } @@ -562,7 +583,10 @@ site->n = n + marked; /* if the curve is closing on a hole, need to make a downslit */ if (fwd < 0 && !(data[edge] & (jedge ? J_BNDY : I_BNDY))) + { + if (n_kind) kcp[n_kind] += kind_start_slit; return slit_cutter (site, 0, pass2); + } return 3; } else if (pass2) @@ -572,6 +596,7 @@ site->edge = edge; site->left = left; site->n = n + marked; + if (n_kind) kcp[n_kind] += kind_start_slit; return slit_cutter (site, heads_up, pass2); } } @@ -649,6 +674,7 @@ const double *y = pass2 ? site->y : 0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; + short *kcp = pass2 ? site->kcp : 0; if (up) { @@ -677,6 +703,7 @@ } xcp[n] = x[p1]; ycp[n] = y[p1]; + kcp[n] = kind_slit_up; n++; p1 += imax; } @@ -733,6 +760,7 @@ { xcp[n] = x[p0]; ycp[n] = y[p0]; + kcp[n] = kind_slit_down; n++; } else @@ -1230,6 +1258,7 @@ site->triangle = NULL; site->xcp = NULL; site->ycp = NULL; + site->kcp = NULL; site->x = NULL; site->y = NULL; site->z = NULL; @@ -1279,6 +1308,7 @@ site->z = z; site->xcp = NULL; site->ycp = NULL; + site->kcp = NULL; return 0; } @@ -1291,11 +1321,12 @@ site = NULL; } -/* Build a list of lists of points, where each point is an (x,y) +/* Build a list of lists of points, where each point is an (x,y,k) tuple. */ static PyObject * -build_cntr_list_p(long *np, double *xp, double *yp, int nparts, long ntotal) +build_cntr_list_p(long *np, double *xp, double *yp, short *kp, + int nparts, long ntotal) { PyObject *point, *contourList, *all_contours; int start = 0, end = 0; @@ -1310,7 +1341,7 @@ contourList = PyList_New(np[i]); for (k = 0, j = start; j < end; j++, k++) { - point = Py_BuildValue("(dd)", xp[j], yp[j]); + point = Py_BuildValue("(ddh)", xp[j], yp[j], kp[j]); if (PyList_SetItem(contourList, k, point)) goto error; } if (PyList_SetItem(all_contours, i, contourList)) goto error; @@ -1323,73 +1354,43 @@ } -#if 0 -/* the following function is not used, so it produces a warning - * commented it out NN - 070630 */ - -/* Build a list of tuples (X, Y), where X and Y are 1-D arrays. */ +/* Build a list of XY 2-D arrays, shape (N,2), to which a list of K arrays + is concatenated concatenated. */ static PyObject * -build_cntr_list_v(long *np, double *xp, double *yp, int nparts, long ntotal) +build_cntr_list_v2(long *np, double *xp, double *yp, short *kp, + int nparts, long ntotal) { - PyObject *point, *all_contours; - PyArrayObject *xv, *yv; - npy_intp dims[1]; - int i; - long j, k; - - all_contours = PyList_New(nparts); - - k = 0; - for (i = 0; i < nparts; i++) - { - dims[0] = np[i]; - xv = (PyArrayObject *) PyArray_SimpleNew(1, dims, PyArray_DOUBLE); - yv = (PyArrayObject *) PyArray_SimpleNew(1, dims, PyArray_DOUBLE); - if (xv == NULL || yv == NULL) goto error; - for (j = 0; j < dims[0]; j++) - { - ((double *)xv->data)[j] = xp[k]; - ((double *)yv->data)[j] = yp[k]; - k++; - } - point = Py_BuildValue("(NN)", xv, yv); - /* "O" increments ref count; "N" does not. */ - if (PyList_SetItem(all_contours, i, point)) goto error; - } - return all_contours; - - error: - Py_XDECREF(all_contours); - return NULL; -} -#endif - -/* Build a list of XY 2-D arrays, shape (N,2) */ -static PyObject * -build_cntr_list_v2(long *np, double *xp, double *yp, int nparts, long ntotal) -{ PyObject *all_contours; PyArrayObject *xyv; + PyArrayObject *kv; npy_intp dims[2]; + npy_intp kdims[1]; int i; long j, k; - all_contours = PyList_New(nparts); + all_contours = PyList_New(nparts*2); k = 0; for (i = 0; i < nparts; i++) { dims[0] = np[i]; dims[1] = 2; + kdims[0] = np[i]; xyv = (PyArrayObject *) PyArray_SimpleNew(2, dims, PyArray_DOUBLE); if (xyv == NULL) goto error; + kv = (PyArrayObject *) PyArray_SimpleNew(1, kdims, PyArray_SHORT); + if (kv == NULL) goto error; + for (j = 0; j < dims[0]; j++) { ((double *)xyv->data)[2*j] = xp[k]; ((double *)xyv->data)[2*j+1] = yp[k]; + ((short *)kv->data)[j] = kp[k]; k++; } if (PyList_SetItem(all_contours, i, (PyObject *)xyv)) goto error; + if (PyList_SetItem(all_contours, nparts+i, + (PyObject *)kv)) goto error; } return all_contours; @@ -1413,6 +1414,7 @@ PyObject *c_list = NULL; double *xp0; double *yp0; + short *kp0; long *nseg0; int iseg; @@ -1451,12 +1453,14 @@ } xp0 = (double *) PyMem_Malloc(ntotal * sizeof(double)); yp0 = (double *) PyMem_Malloc(ntotal * sizeof(double)); + kp0 = (short *) PyMem_Malloc(ntotal * sizeof(short)); nseg0 = (long *) PyMem_Malloc(nparts * sizeof(long)); - if (xp0 == NULL || yp0 == NULL || nseg0 == NULL) goto error; + if (xp0 == NULL || yp0 == NULL || kp0 == NULL || nseg0 == NULL) goto error; /* second pass */ site->xcp = xp0; site->ycp = yp0; + site->kcp = kp0; iseg = 0; for (;;iseg++) { @@ -1475,6 +1479,7 @@ nseg0[iseg] = n; site->xcp += n; site->ycp += n; + site->kcp += n; ntotal2 += n; nparts2++; } @@ -1487,21 +1492,31 @@ } - if (points) + if (points) /* It is False when called; we don't need the point version */ { - c_list = build_cntr_list_p(nseg0, xp0, yp0, nparts, ntotal); + c_list = build_cntr_list_p(nseg0, xp0, yp0, kp0, nparts, ntotal); } else { - c_list = build_cntr_list_v2(nseg0, xp0, yp0, nparts, ntotal); + c_list = build_cntr_list_v2(nseg0, xp0, yp0, kp0, nparts, ntotal); } - PyMem_Free(xp0); PyMem_Free(yp0); PyMem_Free(nseg0); - site->xcp = NULL; site->ycp = NULL; + PyMem_Free(xp0); + PyMem_Free(yp0); + PyMem_Free(kp0); + PyMem_Free(nseg0); + site->xcp = NULL; + site->ycp = NULL; + site->kcp = NULL; return c_list; error: - PyMem_Free(xp0); PyMem_Free(yp0); PyMem_Free(nseg0); - site->xcp = NULL; site->ycp = NULL; + PyMem_Free(xp0); + PyMem_Free(yp0); + PyMem_Free(kp0); + PyMem_Free(nseg0); + site->xcp = NULL; + site->ycp = NULL; + site->kcp = NULL; Py_XDECREF(c_list); return NULL; } @@ -1603,16 +1618,14 @@ } xpa = (PyArrayObject *) PyArray_ContiguousFromObject(xarg, - PyArray_DOUBLE, 2, 2); + PyArray_DOUBLE, 2, 2); ypa = (PyArrayObject *) PyArray_ContiguousFromObject(yarg, - PyArray_DOUBLE, - 2, 2); - zpa = (PyArrayObject *) PyArray_ContiguousFromObject(zarg, PyArray_DOUBLE, - 2, 2); + PyArray_DOUBLE, 2, 2); + zpa = (PyArrayObject *) PyArray_ContiguousFromObject(zarg, + PyArray_DOUBLE, 2, 2); if (marg) mpa = (PyArrayObject *) PyArray_ContiguousFromObject(marg, - PyArray_SBYTE, - 2, 2); + PyArray_SBYTE, 2, 2); else mpa = NULL; @@ -1751,7 +1764,8 @@ if (m == NULL) return; - + PyModule_AddIntConstant(m, "_slitkind", (long)kind_slit_up ); + /* We can add all the point_kinds values later if we need them. */ import_array(); Py_INCREF(&CntrType); PyModule_AddObject(m, "Cntr", (PyObject *)&CntrType); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |