From: <ef...@us...> - 2010-01-16 17:45:38
|
Revision: 8081 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8081&view=rev Author: efiring Date: 2010-01-16 17:45:32 +0000 (Sat, 16 Jan 2010) Log Message: ----------- Patch by Ian Thomas fixes 2 major cntr.c problems: Now line contours coincide with filled contour boundaries, and interior masked regions are handled correctly by contourf. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/pylab_examples/contourf_demo.py trunk/matplotlib/src/cntr.c Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2010-01-11 19:55:26 UTC (rev 8080) +++ trunk/matplotlib/CHANGELOG 2010-01-16 17:45:32 UTC (rev 8081) @@ -1,10 +1,14 @@ -2009-01-11 The color of legend patch follows the rc parameters +2010-01-16 Applied patch by Ian Thomas to fix two contouring + problems: now contourf handles interior masked regions, + and the boundaries of line and filled contours coincide. - EF + +2009-01-11 The color of legend patch follows the rc parameters axes.facecolor and axes.edgecolor. -JJL -2009-01-11 adjustable of Axes can be "box-forced" which allow +2009-01-11 adjustable of Axes can be "box-forced" which allow sharing axes. -JJL -2009-01-11 Add add_click and pop_click methods in +2009-01-11 Add add_click and pop_click methods in BlockingContourLabeler. -JJL 2010-01-03 Added rcParams['axes.color_cycle'] - EF Modified: trunk/matplotlib/examples/pylab_examples/contourf_demo.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/contourf_demo.py 2010-01-11 19:55:26 UTC (rev 8080) +++ trunk/matplotlib/examples/pylab_examples/contourf_demo.py 2010-01-16 17:45:32 UTC (rev 8081) @@ -3,35 +3,14 @@ origin = 'lower' #origin = 'upper' -# The following controls only interior masking. -test_masking = False # There is a bug in filled contour masking with - # interior masks. +delta = 0.025 -if test_masking: - # Use a coarse grid so only a few masked points are needed. - delta = 0.5 -else: - delta = 0.025 - x = y = arange(-3.0, 3.01, delta) X, Y = meshgrid(x, y) Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) Z = 10 * (Z1 - Z2) -# interior badmask doesn't work yet for filled contours -if test_masking: - badmask = zeros(shape(Z)) - - badmask[5,5] = 1 - badmask[5,6] = 1 - Z[5,5] = 0 - Z[5,6] = 0 - - badmask[0,0] = 1 - Z[0,0] = 0 - Z = ma.array(Z, mask=badmask) - nr, nc = Z.shape # put NaNs in one corner: @@ -43,7 +22,11 @@ # mask another corner: Z[:nr//6, :nc//6] = ma.masked +# mask a circle in the middle: +interior = sqrt((X**2) + (Y**2)) < 0.5 +Z[interior] = ma.masked + # We are using automatic selection of contour levels; # this is usually not such a good idea, because they don't # occur on nice boundaries, but we do it here for purposes @@ -63,7 +46,7 @@ origin=origin, hold='on') -title('Nonsense (with 2 masked corners)') +title('Nonsense (3 masked regions)') xlabel('word length anomaly') ylabel('sentence length anomaly') @@ -87,7 +70,7 @@ colors = ('k',), linewidths = (3,), origin = origin) -title('Listed colors (with 2 masked corners)') +title('Listed colors (3 masked regions)') clabel(CS4, fmt = '%2.1f', colors = 'w', fontsize=14) colorbar(CS3) Modified: trunk/matplotlib/src/cntr.c =================================================================== --- trunk/matplotlib/src/cntr.c 2010-01-11 19:55:26 UTC (rev 8080) +++ trunk/matplotlib/src/cntr.c 2010-01-16 17:45:32 UTC (rev 8081) @@ -50,12 +50,14 @@ * The problem is that two disjoint curves cut through a saddle zone * (I reject the alternative of connecting the opposite points to make * a single self-intersecting curve, since those make ugly contour plots - * -- I've tried it). The real problem with saddle zones is that you - * need to communicate the connectivity decision you make back to the - * calling routine, since for the next contour level, we need to tell - * the contour tracer to make the same decision as on the previous - * level. The input/output triangulation array is the solution to this - * nasty problem. + * -- I've tried it). The solution is to determine the z value of the + * centre of the zone, which is the mean of the z values of the four + * corner points. If the centre z is higher than the contour level of + * interest and you are moving along the line with higher values on the + * left, turn right to leave the saddle zone. If the centre z is lower + * than the contour level turn left. Whether the centre z is higher + * than the 1 or 2 contour levels is stored in the saddle array so that + * it does not need to be recalculated in subsequent passes. * * Another complicating factor is that there may be logical holes in * the mesh -- zones which do not exist. We want our contours to stop @@ -175,6 +177,11 @@ * or not, z value 0, 1, or 2 -- is kept in a mesh sized data array */ typedef short Cdata; +/* information to decide on correct contour direction in saddle zones + * is stored in a mesh sized array. Only those entries corresponding + * to saddle zones have nonzero values in this array. */ +typedef char Saddle; + /* here is the minimum structure required to tell where we are in the * mesh sized data array */ typedef struct Csite Csite; @@ -189,8 +196,8 @@ long count; /* count of start markers visited */ double zlevel[2]; /* contour levels, zlevel[1]<=zlevel[0] * signals single level case */ - short *triangle; /* triangulation array for the mesh */ - char *reg; /* region array for the mesh (was int) */ + Saddle *saddle; /* saddle zone information for the mesh */ + char *reg; /* region array for the mesh (was int) */ Cdata *data; /* added by EF */ long edge0, left0; /* starting site on this curve for closure */ int level0; /* starting level for closure */ @@ -225,8 +232,6 @@ printf("\n"); } -/* triangle only takes values of -1, 0, 1, so it could be a signed char. */ -/* most or all of the longs probably could be converted to ints with no loss */ /* the Cdata array consists of the following bits: * Z_VALUE (2 bits) 0, 1, or 2 function value at point @@ -243,6 +248,7 @@ * OPEN_END marks an i-edge start point whose other endpoint is * on a boundary for the single level case * ALL_DONE marks final start point + * SLIT_DN_VISITED this slit downstroke hasn't/has been visited in pass 2 */ #define Z_VALUE 0x0003 #define ZONE_EX 0x0004 @@ -257,6 +263,7 @@ #define SLIT_DN 0x0800 #define OPEN_END 0x1000 #define ALL_DONE 0x2000 +#define SLIT_DN_VISITED 0x4000 /* some helpful macros to find points relative to a given directed * edge -- points are designated 0, 1, 2, 3 CCW around zone with 0 and @@ -272,6 +279,15 @@ enum {kind_zone, kind_edge1, kind_edge2, kind_slit_up, kind_slit_down, kind_start_slit=16} point_kinds; +/* Saddle zone array consists of the following bits: + * SADDLE_SET whether zone's saddle data has been set. + * SADDLE_GT0 whether z of centre of zone is higher than site->level[0]. + * SADDLE_GT1 whether z of centre of zone is higher than site->level[1]. + */ +#define SADDLE_SET 0x01 +#define SADDLE_GT0 0x02 +#define SADDLE_GT1 0x04 + /* ------------------------------------------------------------------------ */ /* these actually mark points */ @@ -313,18 +329,17 @@ long left0 = site->left0; int level0 = site->level0 == level; int two_levels = site->zlevel[1] > site->zlevel[0]; - short *triangle = site->triangle; + Saddle* saddle = site->saddle; const double *x = pass2 ? site->x : 0; const double *y = pass2 ? site->y : 0; - const double *z = pass2 ? site->z : 0; - double zlevel = pass2 ? site->zlevel[level] : 0.0; + const double *z = site->z; + double zlevel = site->zlevel[level]; 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 */ int done = 0; int n_kind; @@ -402,29 +417,28 @@ { if (z1 == z3) { - /* this is a saddle zone, need triangle to decide - * -- set triangle if not already decided for this zone */ + /* this is a saddle zone, determine whether to turn left or + * right depending on height of centre of zone relative to + * contour level. Set saddle[zone] if not already decided. */ long zone = edge + (left > 0 ? left : 0); - if (triangle) + if (!(saddle[zone] & SADDLE_SET)) { - if (!triangle[zone]) - { - if (keep_left) - triangle[zone] = jedge ? -1 : 1; - else - triangle[zone] = jedge ? 1 : -1; - } - if (triangle[zone] > 0 ? !jedge : jedge) - goto bkwd; + saddle[zone] = SADDLE_SET; + double zcentre = (z[p0] + z[p0+left] + z[p1] + z[p1+left])/4.0; + if (zcentre > site->zlevel[0]) + saddle[zone] |= + (two_levels && zcentre > site->zlevel[1]) + ? SADDLE_GT0 | SADDLE_GT1 : SADDLE_GT0; } - else - { - if (keep_left) - goto bkwd; - } + + int turnRight = level == 2 ? (saddle[zone] & SADDLE_GT1) + : (saddle[zone] & SADDLE_GT0); + if (z1 ^ (level == 2)) + turnRight = !turnRight; + if (!turnRight) + goto bkwd; } /* bend forward (right along curve) */ - keep_left = 1; jedge = !jedge; edge = p1 + (left > 0 ? left : 0); { @@ -437,7 +451,6 @@ { bkwd: /* bend backward (left along curve) */ - keep_left = 0; jedge = !jedge; edge = p0 + (left > 0 ? left : 0); { @@ -590,17 +603,27 @@ if (n_kind) kcp[n_kind] += kind_start_slit; return slit_cutter (site, 0, pass2); } + if (fwd < 0 && level0 && left < 0) + { + if (n_kind) kcp[n_kind] += kind_start_slit; + return slit_cutter (site, 0, pass2); + } return 3; } else if (pass2) { if (heads_up || (fwd < 0 && (data[edge] & SLIT_DN))) { - 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); + if (!heads_up && !(data[edge] & SLIT_DN_VISITED)) + data[edge] |= SLIT_DN_VISITED; + else + { + 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); + } } } else @@ -1181,6 +1204,8 @@ /* place immediate stop mark if nothing found */ if (!count) data[0] |= ALL_DONE; + else + for (i = 0; i < ijmax; ++i) site->saddle[i] = 0; /* initialize site */ site->edge0 = site->edge00 = site->edge = 0; @@ -1252,7 +1277,7 @@ if (site == NULL) return NULL; site->data = NULL; site->reg = NULL; - site->triangle = NULL; + site->saddle = NULL; site->xcp = NULL; site->ycp = NULL; site->kcp = NULL; @@ -1268,7 +1293,6 @@ { long ijmax = iMax * jMax; long nreg = iMax * jMax + iMax + 1; - long i; site->imax = iMax; site->jmax = jMax; @@ -1278,21 +1302,20 @@ PyMem_Free(site); return -1; } - site->triangle = (short *) PyMem_Malloc(sizeof(short) * ijmax); - if (site->triangle == NULL) + site->saddle = (Saddle*) PyMem_Malloc(sizeof(Saddle) * ijmax); + if (site->saddle == NULL) { PyMem_Free(site->data); PyMem_Free(site); return -1; } - for (i = 0; i < ijmax; i++) site->triangle[i] = 0; site->reg = NULL; if (mask != NULL) { site->reg = (char *) PyMem_Malloc(sizeof(char) * nreg); if (site->reg == NULL) { - PyMem_Free(site->triangle); + PyMem_Free(site->saddle); PyMem_Free(site->data); PyMem_Free(site); return -1; @@ -1311,7 +1334,7 @@ void cntr_del(Csite *site) { - PyMem_Free(site->triangle); + PyMem_Free(site->saddle); PyMem_Free(site->reg); PyMem_Free(site->data); PyMem_Free(site); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |