13
13
import numpy as np
14
14
from numpy import ma
15
15
import matplotlib ._cntr as _cntr
16
+ import matplotlib ._contour as _contour
16
17
import matplotlib .path as mpath
17
18
import matplotlib .ticker as ticker
18
19
import matplotlib .cm as cm
@@ -989,9 +990,10 @@ def get_transform(self):
989
990
990
991
def __getstate__ (self ):
991
992
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
995
997
return state
996
998
997
999
def legend_elements (self , variable_name = 'x' , str_format = str ):
@@ -1433,18 +1435,34 @@ def _process_args(self, *args, **kwargs):
1433
1435
Process args and kwargs.
1434
1436
"""
1435
1437
if isinstance (args [0 ], QuadContourSet ):
1436
- C = args [0 ].Cntr
1437
1438
if self .levels is None :
1438
1439
self .levels = args [0 ].levels
1439
1440
self .zmin = args [0 ].zmin
1440
1441
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
1441
1447
else :
1442
1448
x , y , z = self ._contour_args (args , kwargs )
1443
1449
1444
1450
_mask = ma .getmask (z )
1445
- if _mask is ma .nomask :
1451
+ if _mask is ma .nomask or not _mask . any () :
1446
1452
_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 )
1448
1466
1449
1467
t = self .get_transform ()
1450
1468
@@ -1465,7 +1483,10 @@ def _process_args(self, *args, **kwargs):
1465
1483
self .ax .update_datalim ([(x0 , y0 ), (x1 , y1 )])
1466
1484
self .ax .autoscale_view (tight = True )
1467
1485
1468
- self .Cntr = C
1486
+ if self ._corner_mask == 'legacy' :
1487
+ self .Cntr = contour_generator
1488
+ else :
1489
+ self ._contour_generator = contour_generator
1469
1490
1470
1491
def _get_allsegs_and_allkinds (self ):
1471
1492
"""
@@ -1476,20 +1497,28 @@ def _get_allsegs_and_allkinds(self):
1476
1497
lowers , uppers = self ._get_lowers_and_uppers ()
1477
1498
allkinds = []
1478
1499
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 )
1485
1511
allkinds .append (kinds )
1486
1512
else :
1487
1513
allkinds = None
1488
1514
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 )
1493
1522
return allsegs , allkinds
1494
1523
1495
1524
def _contour_args (self , args , kwargs ):
@@ -1672,6 +1701,20 @@ def _initialize_x_y(self, z):
1672
1701
1673
1702
Optional keyword arguments:
1674
1703
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
+
1675
1718
*colors*: [ *None* | string | (mpl_colors) ]
1676
1719
If *None*, the colormap specified by cmap will be used.
1677
1720
@@ -1750,6 +1793,15 @@ def _initialize_x_y(self, z):
1750
1793
filled contours, the default is *True*. For line contours,
1751
1794
it is taken from rcParams['lines.antialiased'].
1752
1795
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
+
1753
1805
contour-only keyword arguments:
1754
1806
1755
1807
*linewidths*: [ *None* | number | tuple of numbers ]
@@ -1774,13 +1826,6 @@ def _initialize_x_y(self, z):
1774
1826
1775
1827
contourf-only keyword arguments:
1776
1828
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
-
1784
1829
*hatches*:
1785
1830
A list of cross hatch patterns to use on the filled areas.
1786
1831
If None, no hatching will be added to the contour.
@@ -1802,4 +1847,6 @@ def _initialize_x_y(self, z):
1802
1847
.. plot:: mpl_examples/pylab_examples/contour_demo.py
1803
1848
1804
1849
.. plot:: mpl_examples/pylab_examples/contourf_demo.py
1850
+
1851
+ .. plot:: mpl_examples/pylab_examples/contour_corner_mask.py
1805
1852
"""
0 commit comments