Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e5bc430

Browse files
committed
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. svn path=/trunk/matplotlib/; revision=8081
1 parent a2f63e8 commit e5bc430

3 files changed

Lines changed: 82 additions & 72 deletions

File tree

CHANGELOG

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
2009-01-11 The color of legend patch follows the rc parameters
1+
2010-01-16 Applied patch by Ian Thomas to fix two contouring
2+
problems: now contourf handles interior masked regions,
3+
and the boundaries of line and filled contours coincide. - EF
4+
5+
2009-01-11 The color of legend patch follows the rc parameters
26
axes.facecolor and axes.edgecolor. -JJL
37

4-
2009-01-11 adjustable of Axes can be "box-forced" which allow
8+
2009-01-11 adjustable of Axes can be "box-forced" which allow
59
sharing axes. -JJL
610

7-
2009-01-11 Add add_click and pop_click methods in
11+
2009-01-11 Add add_click and pop_click methods in
812
BlockingContourLabeler. -JJL
913

1014
2010-01-03 Added rcParams['axes.color_cycle'] - EF

examples/pylab_examples/contourf_demo.py

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,14 @@
33
origin = 'lower'
44
#origin = 'upper'
55

6-
# The following controls only interior masking.
7-
test_masking = False # There is a bug in filled contour masking with
8-
# interior masks.
9-
10-
if test_masking:
11-
# Use a coarse grid so only a few masked points are needed.
12-
delta = 0.5
13-
else:
14-
delta = 0.025
6+
delta = 0.025
157

168
x = y = arange(-3.0, 3.01, delta)
179
X, Y = meshgrid(x, y)
1810
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
1911
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
2012
Z = 10 * (Z1 - Z2)
2113

22-
# interior badmask doesn't work yet for filled contours
23-
if test_masking:
24-
badmask = zeros(shape(Z))
25-
26-
badmask[5,5] = 1
27-
badmask[5,6] = 1
28-
Z[5,5] = 0
29-
Z[5,6] = 0
30-
31-
badmask[0,0] = 1
32-
Z[0,0] = 0
33-
Z = ma.array(Z, mask=badmask)
34-
3514
nr, nc = Z.shape
3615

3716
# put NaNs in one corner:
@@ -43,6 +22,10 @@
4322
# mask another corner:
4423
Z[:nr//6, :nc//6] = ma.masked
4524

25+
# mask a circle in the middle:
26+
interior = sqrt((X**2) + (Y**2)) < 0.5
27+
Z[interior] = ma.masked
28+
4629

4730
# We are using automatic selection of contour levels;
4831
# this is usually not such a good idea, because they don't
@@ -63,7 +46,7 @@
6346
origin=origin,
6447
hold='on')
6548

66-
title('Nonsense (with 2 masked corners)')
49+
title('Nonsense (3 masked regions)')
6750
xlabel('word length anomaly')
6851
ylabel('sentence length anomaly')
6952

@@ -87,7 +70,7 @@
8770
colors = ('k',),
8871
linewidths = (3,),
8972
origin = origin)
90-
title('Listed colors (with 2 masked corners)')
73+
title('Listed colors (3 masked regions)')
9174
clabel(CS4, fmt = '%2.1f', colors = 'w', fontsize=14)
9275
colorbar(CS3)
9376

src/cntr.c

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@
5050
* The problem is that two disjoint curves cut through a saddle zone
5151
* (I reject the alternative of connecting the opposite points to make
5252
* a single self-intersecting curve, since those make ugly contour plots
53-
* -- I've tried it). The real problem with saddle zones is that you
54-
* need to communicate the connectivity decision you make back to the
55-
* calling routine, since for the next contour level, we need to tell
56-
* the contour tracer to make the same decision as on the previous
57-
* level. The input/output triangulation array is the solution to this
58-
* nasty problem.
53+
* -- I've tried it). The solution is to determine the z value of the
54+
* centre of the zone, which is the mean of the z values of the four
55+
* corner points. If the centre z is higher than the contour level of
56+
* interest and you are moving along the line with higher values on the
57+
* left, turn right to leave the saddle zone. If the centre z is lower
58+
* than the contour level turn left. Whether the centre z is higher
59+
* than the 1 or 2 contour levels is stored in the saddle array so that
60+
* it does not need to be recalculated in subsequent passes.
5961
*
6062
* Another complicating factor is that there may be logical holes in
6163
* the mesh -- zones which do not exist. We want our contours to stop
@@ -175,6 +177,11 @@
175177
* or not, z value 0, 1, or 2 -- is kept in a mesh sized data array */
176178
typedef short Cdata;
177179

180+
/* information to decide on correct contour direction in saddle zones
181+
* is stored in a mesh sized array. Only those entries corresponding
182+
* to saddle zones have nonzero values in this array. */
183+
typedef char Saddle;
184+
178185
/* here is the minimum structure required to tell where we are in the
179186
* mesh sized data array */
180187
typedef struct Csite Csite;
@@ -189,8 +196,8 @@ struct Csite
189196
long count; /* count of start markers visited */
190197
double zlevel[2]; /* contour levels, zlevel[1]<=zlevel[0]
191198
* signals single level case */
192-
short *triangle; /* triangulation array for the mesh */
193-
char *reg; /* region array for the mesh (was int) */
199+
Saddle *saddle; /* saddle zone information for the mesh */
200+
char *reg; /* region array for the mesh (was int) */
194201
Cdata *data; /* added by EF */
195202
long edge0, left0; /* starting site on this curve for closure */
196203
int level0; /* starting level for closure */
@@ -225,8 +232,6 @@ void print_Csite(Csite *Csite)
225232
printf("\n");
226233
}
227234

228-
/* triangle only takes values of -1, 0, 1, so it could be a signed char. */
229-
/* most or all of the longs probably could be converted to ints with no loss */
230235

231236
/* the Cdata array consists of the following bits:
232237
* Z_VALUE (2 bits) 0, 1, or 2 function value at point
@@ -243,6 +248,7 @@ void print_Csite(Csite *Csite)
243248
* OPEN_END marks an i-edge start point whose other endpoint is
244249
* on a boundary for the single level case
245250
* ALL_DONE marks final start point
251+
* SLIT_DN_VISITED this slit downstroke hasn't/has been visited in pass 2
246252
*/
247253
#define Z_VALUE 0x0003
248254
#define ZONE_EX 0x0004
@@ -257,6 +263,7 @@ void print_Csite(Csite *Csite)
257263
#define SLIT_DN 0x0800
258264
#define OPEN_END 0x1000
259265
#define ALL_DONE 0x2000
266+
#define SLIT_DN_VISITED 0x4000
260267

261268
/* some helpful macros to find points relative to a given directed
262269
* edge -- points are designated 0, 1, 2, 3 CCW around zone with 0 and
@@ -272,6 +279,15 @@ void print_Csite(Csite *Csite)
272279
enum {kind_zone, kind_edge1, kind_edge2,
273280
kind_slit_up, kind_slit_down, kind_start_slit=16} point_kinds;
274281

282+
/* Saddle zone array consists of the following bits:
283+
* SADDLE_SET whether zone's saddle data has been set.
284+
* SADDLE_GT0 whether z of centre of zone is higher than site->level[0].
285+
* SADDLE_GT1 whether z of centre of zone is higher than site->level[1].
286+
*/
287+
#define SADDLE_SET 0x01
288+
#define SADDLE_GT0 0x02
289+
#define SADDLE_GT1 0x04
290+
275291
/* ------------------------------------------------------------------------ */
276292

277293
/* these actually mark points */
@@ -313,18 +329,17 @@ zone_crosser (Csite * site, int level, int pass2)
313329
long left0 = site->left0;
314330
int level0 = site->level0 == level;
315331
int two_levels = site->zlevel[1] > site->zlevel[0];
316-
short *triangle = site->triangle;
332+
Saddle* saddle = site->saddle;
317333

318334
const double *x = pass2 ? site->x : 0;
319335
const double *y = pass2 ? site->y : 0;
320-
const double *z = pass2 ? site->z : 0;
321-
double zlevel = pass2 ? site->zlevel[level] : 0.0;
336+
const double *z = site->z;
337+
double zlevel = site->zlevel[level];
322338
double *xcp = pass2 ? site->xcp : 0;
323339
double *ycp = pass2 ? site->ycp : 0;
324340
short *kcp = pass2 ? site->kcp : 0;
325341

326342
int z0, z1, z2, z3;
327-
int keep_left = 0; /* flag to try to minimize curvature in saddles */
328343
int done = 0;
329344
int n_kind;
330345

@@ -402,29 +417,28 @@ zone_crosser (Csite * site, int level, int pass2)
402417
{
403418
if (z1 == z3)
404419
{
405-
/* this is a saddle zone, need triangle to decide
406-
* -- set triangle if not already decided for this zone */
420+
/* this is a saddle zone, determine whether to turn left or
421+
* right depending on height of centre of zone relative to
422+
* contour level. Set saddle[zone] if not already decided. */
407423
long zone = edge + (left > 0 ? left : 0);
408-
if (triangle)
424+
if (!(saddle[zone] & SADDLE_SET))
409425
{
410-
if (!triangle[zone])
411-
{
412-
if (keep_left)
413-
triangle[zone] = jedge ? -1 : 1;
414-
else
415-
triangle[zone] = jedge ? 1 : -1;
416-
}
417-
if (triangle[zone] > 0 ? !jedge : jedge)
418-
goto bkwd;
419-
}
420-
else
421-
{
422-
if (keep_left)
423-
goto bkwd;
426+
saddle[zone] = SADDLE_SET;
427+
double zcentre = (z[p0] + z[p0+left] + z[p1] + z[p1+left])/4.0;
428+
if (zcentre > site->zlevel[0])
429+
saddle[zone] |=
430+
(two_levels && zcentre > site->zlevel[1])
431+
? SADDLE_GT0 | SADDLE_GT1 : SADDLE_GT0;
424432
}
433+
434+
int turnRight = level == 2 ? (saddle[zone] & SADDLE_GT1)
435+
: (saddle[zone] & SADDLE_GT0);
436+
if (z1 ^ (level == 2))
437+
turnRight = !turnRight;
438+
if (!turnRight)
439+
goto bkwd;
425440
}
426441
/* bend forward (right along curve) */
427-
keep_left = 1;
428442
jedge = !jedge;
429443
edge = p1 + (left > 0 ? left : 0);
430444
{
@@ -437,7 +451,6 @@ zone_crosser (Csite * site, int level, int pass2)
437451
{
438452
bkwd:
439453
/* bend backward (left along curve) */
440-
keep_left = 0;
441454
jedge = !jedge;
442455
edge = p0 + (left > 0 ? left : 0);
443456
{
@@ -590,17 +603,27 @@ edge_walker (Csite * site, int pass2)
590603
if (n_kind) kcp[n_kind] += kind_start_slit;
591604
return slit_cutter (site, 0, pass2);
592605
}
606+
if (fwd < 0 && level0 && left < 0)
607+
{
608+
if (n_kind) kcp[n_kind] += kind_start_slit;
609+
return slit_cutter (site, 0, pass2);
610+
}
593611
return 3;
594612
}
595613
else if (pass2)
596614
{
597615
if (heads_up || (fwd < 0 && (data[edge] & SLIT_DN)))
598616
{
599-
site->edge = edge;
600-
site->left = left;
601-
site->n = n + marked;
602-
if (n_kind) kcp[n_kind] += kind_start_slit;
603-
return slit_cutter (site, heads_up, pass2);
617+
if (!heads_up && !(data[edge] & SLIT_DN_VISITED))
618+
data[edge] |= SLIT_DN_VISITED;
619+
else
620+
{
621+
site->edge = edge;
622+
site->left = left;
623+
site->n = n + marked;
624+
if (n_kind) kcp[n_kind] += kind_start_slit;
625+
return slit_cutter (site, heads_up, pass2);
626+
}
604627
}
605628
}
606629
else
@@ -1181,6 +1204,8 @@ data_init (Csite * site, long nchunk)
11811204
/* place immediate stop mark if nothing found */
11821205
if (!count)
11831206
data[0] |= ALL_DONE;
1207+
else
1208+
for (i = 0; i < ijmax; ++i) site->saddle[i] = 0;
11841209

11851210
/* initialize site */
11861211
site->edge0 = site->edge00 = site->edge = 0;
@@ -1252,7 +1277,7 @@ cntr_new(void)
12521277
if (site == NULL) return NULL;
12531278
site->data = NULL;
12541279
site->reg = NULL;
1255-
site->triangle = NULL;
1280+
site->saddle = NULL;
12561281
site->xcp = NULL;
12571282
site->ycp = NULL;
12581283
site->kcp = NULL;
@@ -1268,7 +1293,6 @@ cntr_init(Csite *site, long iMax, long jMax, double *x, double *y,
12681293
{
12691294
long ijmax = iMax * jMax;
12701295
long nreg = iMax * jMax + iMax + 1;
1271-
long i;
12721296

12731297
site->imax = iMax;
12741298
site->jmax = jMax;
@@ -1278,21 +1302,20 @@ cntr_init(Csite *site, long iMax, long jMax, double *x, double *y,
12781302
PyMem_Free(site);
12791303
return -1;
12801304
}
1281-
site->triangle = (short *) PyMem_Malloc(sizeof(short) * ijmax);
1282-
if (site->triangle == NULL)
1305+
site->saddle = (Saddle*) PyMem_Malloc(sizeof(Saddle) * ijmax);
1306+
if (site->saddle == NULL)
12831307
{
12841308
PyMem_Free(site->data);
12851309
PyMem_Free(site);
12861310
return -1;
12871311
}
1288-
for (i = 0; i < ijmax; i++) site->triangle[i] = 0;
12891312
site->reg = NULL;
12901313
if (mask != NULL)
12911314
{
12921315
site->reg = (char *) PyMem_Malloc(sizeof(char) * nreg);
12931316
if (site->reg == NULL)
12941317
{
1295-
PyMem_Free(site->triangle);
1318+
PyMem_Free(site->saddle);
12961319
PyMem_Free(site->data);
12971320
PyMem_Free(site);
12981321
return -1;
@@ -1311,7 +1334,7 @@ cntr_init(Csite *site, long iMax, long jMax, double *x, double *y,
13111334

13121335
void cntr_del(Csite *site)
13131336
{
1314-
PyMem_Free(site->triangle);
1337+
PyMem_Free(site->saddle);
13151338
PyMem_Free(site->reg);
13161339
PyMem_Free(site->data);
13171340
PyMem_Free(site);

0 commit comments

Comments
 (0)