1313import numpy as np
1414from numpy import ma
1515import matplotlib ._cntr as _cntr
16+ import matplotlib ._contour as _contour
1617import matplotlib .path as mpath
1718import matplotlib .ticker as ticker
1819import matplotlib .cm as cm
@@ -989,9 +990,10 @@ def get_transform(self):
989990
990991 def __getstate__ (self ):
991992 state = self .__dict__ .copy ()
992- # the C object Cntr cannot currently be pickled. This isn't a big issue
993- # as it is not actually used once the contour has been calculated
994- state ['Cntr' ] = None
993+ # the C object _contour_generator cannot currently be pickled. This
994+ # isn't a big issue as it is not actually used once the contour has
995+ # been calculated.
996+ state ['_contour_generator' ] = None
995997 return state
996998
997999 def legend_elements (self , variable_name = 'x' , str_format = str ):
@@ -1433,18 +1435,34 @@ def _process_args(self, *args, **kwargs):
14331435 Process args and kwargs.
14341436 """
14351437 if isinstance (args [0 ], QuadContourSet ):
1436- C = args [0 ].Cntr
14371438 if self .levels is None :
14381439 self .levels = args [0 ].levels
14391440 self .zmin = args [0 ].zmin
14401441 self .zmax = args [0 ].zmax
1442+ self ._corner_mask = args [0 ]._corner_mask
1443+ if self ._corner_mask == 'legacy' :
1444+ contour_generator = args [0 ].Cntr
1445+ else :
1446+ contour_generator = args [0 ]._contour_generator
14411447 else :
14421448 x , y , z = self ._contour_args (args , kwargs )
14431449
14441450 _mask = ma .getmask (z )
1445- if _mask is ma .nomask :
1451+ if _mask is ma .nomask or not _mask . any () :
14461452 _mask = None
1447- C = _cntr .Cntr (x , y , z .filled (), _mask )
1453+
1454+ self ._corner_mask = kwargs .get ('corner_mask' , None )
1455+ if self ._corner_mask is None :
1456+ self ._corner_mask = mpl .rcParams ['contour.corner_mask' ]
1457+
1458+ if self ._corner_mask == 'legacy' :
1459+ cbook .warn_deprecated ('1.5' ,
1460+ name = "corner_mask='legacy'" ,
1461+ alternative = 'corner_mask=False or True' )
1462+ contour_generator = _cntr .Cntr (x , y , z .filled (), _mask )
1463+ else :
1464+ contour_generator = _contour .QuadContourGenerator (
1465+ x , y , z .filled (), _mask , self ._corner_mask , self .nchunk )
14481466
14491467 t = self .get_transform ()
14501468
@@ -1465,7 +1483,10 @@ def _process_args(self, *args, **kwargs):
14651483 self .ax .update_datalim ([(x0 , y0 ), (x1 , y1 )])
14661484 self .ax .autoscale_view (tight = True )
14671485
1468- self .Cntr = C
1486+ if self ._corner_mask == 'legacy' :
1487+ self .Cntr = contour_generator
1488+ else :
1489+ self ._contour_generator = contour_generator
14691490
14701491 def _get_allsegs_and_allkinds (self ):
14711492 """
@@ -1476,20 +1497,28 @@ def _get_allsegs_and_allkinds(self):
14761497 lowers , uppers = self ._get_lowers_and_uppers ()
14771498 allkinds = []
14781499 for level , level_upper in zip (lowers , uppers ):
1479- nlist = self .Cntr .trace (level , level_upper ,
1480- nchunk = self .nchunk )
1481- nseg = len (nlist ) // 2
1482- segs = nlist [:nseg ]
1483- kinds = nlist [nseg :]
1484- allsegs .append (segs )
1500+ if self ._corner_mask == 'legacy' :
1501+ nlist = self .Cntr .trace (level , level_upper ,
1502+ nchunk = self .nchunk )
1503+ nseg = len (nlist ) // 2
1504+ vertices = nlist [:nseg ]
1505+ kinds = nlist [nseg :]
1506+ else :
1507+ vertices , kinds = \
1508+ self ._contour_generator .create_filled_contour (
1509+ level , level_upper )
1510+ allsegs .append (vertices )
14851511 allkinds .append (kinds )
14861512 else :
14871513 allkinds = None
14881514 for level in self .levels :
1489- nlist = self .Cntr .trace (level )
1490- nseg = len (nlist ) // 2
1491- segs = nlist [:nseg ]
1492- allsegs .append (segs )
1515+ if self ._corner_mask == 'legacy' :
1516+ nlist = self .Cntr .trace (level )
1517+ nseg = len (nlist ) // 2
1518+ vertices = nlist [:nseg ]
1519+ else :
1520+ vertices = self ._contour_generator .create_contour (level )
1521+ allsegs .append (vertices )
14931522 return allsegs , allkinds
14941523
14951524 def _contour_args (self , args , kwargs ):
@@ -1672,6 +1701,20 @@ def _initialize_x_y(self, z):
16721701
16731702 Optional keyword arguments:
16741703
1704+ *corner_mask*: [ *True* | *False* | 'legacy' ]
1705+ Enable/disable corner masking, which only has an effect if *Z* is
1706+ a masked array. If *False*, any quad touching a masked point is
1707+ masked out. If *True*, only the triangular corners of quads
1708+ nearest those points are always masked out, other triangular
1709+ corners comprising three unmasked points are contoured as usual.
1710+ If 'legacy', the old contouring algorithm is used, which is
1711+ equivalent to *False* and is deprecated, only remaining whilst the
1712+ new algorithm is tested fully.
1713+
1714+ If not specified, the default is taken from
1715+ rcParams['contour.corner_mask'], which is True unless it has
1716+ been modified.
1717+
16751718 *colors*: [ *None* | string | (mpl_colors) ]
16761719 If *None*, the colormap specified by cmap will be used.
16771720
@@ -1750,6 +1793,15 @@ def _initialize_x_y(self, z):
17501793 filled contours, the default is *True*. For line contours,
17511794 it is taken from rcParams['lines.antialiased'].
17521795
1796+ *nchunk*: [ 0 | integer ]
1797+ If 0, no subdivision of the domain. Specify a positive integer to
1798+ divide the domain into subdomains of *nchunk* by *nchunk* quads.
1799+ Chunking reduces the maximum length of polygons generated by the
1800+ contouring algorithm which reduces the rendering workload passed
1801+ on to the backend and also requires slightly less RAM. It can
1802+ however introduce rendering artifacts at chunk boundaries depending
1803+ on the backend, the *antialiased* flag and value of *alpha*.
1804+
17531805 contour-only keyword arguments:
17541806
17551807 *linewidths*: [ *None* | number | tuple of numbers ]
@@ -1774,13 +1826,6 @@ def _initialize_x_y(self, z):
17741826
17751827 contourf-only keyword arguments:
17761828
1777- *nchunk*: [ 0 | integer ]
1778- If 0, no subdivision of the domain. Specify a positive integer to
1779- divide the domain into subdomains of roughly *nchunk* by *nchunk*
1780- points. This may never actually be advantageous, so this option may
1781- be removed. Chunking introduces artifacts at the chunk boundaries
1782- unless *antialiased* is *False*.
1783-
17841829 *hatches*:
17851830 A list of cross hatch patterns to use on the filled areas.
17861831 If None, no hatching will be added to the contour.
@@ -1802,4 +1847,6 @@ def _initialize_x_y(self, z):
18021847 .. plot:: mpl_examples/pylab_examples/contour_demo.py
18031848
18041849 .. plot:: mpl_examples/pylab_examples/contourf_demo.py
1850+
1851+ .. plot:: mpl_examples/pylab_examples/contour_corner_mask.py
18051852 """
0 commit comments