Index: lib/matplotlib/contour.py
===================================================================
--- lib/matplotlib/contour.py	(revision 8226)
+++ lib/matplotlib/contour.py	(working copy)
@@ -577,7 +577,7 @@
 
 class ContourSet(cm.ScalarMappable, ContourLabeler):
     """
-    Create and store a set of contour lines or filled regions.
+    Store a set of contour lines or filled regions.
 
     User-callable method: clabel
 
@@ -592,17 +592,49 @@
         same as levels for line contours; half-way between
         levels for filled contours.  See _process_colors method.
     """
-
-
     def __init__(self, ax, *args, **kwargs):
         """
         Draw contour lines or filled regions, depending on
         whether keyword arg 'filled' is False (default) or True.
 
-        The first argument of the initializer must be an axes
-        object.  The remaining arguments and keyword arguments
-        are described in ContourSet.contour_doc.
+        The first three arguments must be:
 
+          *ax*: axes object.
+
+          *levels*: [level0, level1, ..., leveln]
+            A list of floating point numbers indicating the contour
+            levels.
+
+          *allsegs*: [level0segs, level1segs, ...]
+            List of all the polygon segments for all the *levels*.
+            For contour lines len(allsegs) == len(levels), and for
+            filled contour regions len(allsegs) = len(levels)-1.
+
+            level0segs = [polygon0, polygon1, ...]
+
+            polygon0 = array_like [[x0,y0], [x1,y1], ...]
+
+          *allkinds*: None or [level0kinds, level1kinds, ...]
+            Optional list of all the polygon vertex kinds (code types), as
+            described and used in Path.   This is used to allow multiply-
+            connected paths such as holes within filled polygons.
+            If not None, len(allkinds) == len(allsegs).
+
+            level0kinds = [polygon0kinds, ...]
+
+            polygon0kinds = [vertexcode0, vertexcode1, ...]
+
+            If allkinds is not None, usually all polygons for a particular
+            contour level are grouped together so that
+
+            level0segs = [polygon0] and level0kinds = [polygon0kinds].
+
+        Keyword arguments are as described in
+        :class:`~matplotlib.contour.QuadContourSet` object.
+
+        **Examples:**
+
+        .. plot:: mpl_examples/misc/contour_manual.py
         """
         self.ax = ax
         self.levels = kwargs.get('levels', None)
@@ -638,24 +670,7 @@
             raise ValueError('Either colors or cmap must be None')
         if self.origin == 'image': self.origin = mpl.rcParams['image.origin']
 
-        if isinstance(args[0], ContourSet):
-            C = args[0].Cntr
-            if self.levels is None:
-                self.levels = args[0].levels
-        else:
-            x, y, z = self._contour_args(args, kwargs)
-
-            x0 = ma.minimum(x)
-            x1 = ma.maximum(x)
-            y0 = ma.minimum(y)
-            y1 = ma.maximum(y)
-            self.ax.update_datalim([(x0,y0), (x1,y1)])
-            self.ax.autoscale_view()
-            _mask = ma.getmask(z)
-            if _mask is ma.nomask:
-                _mask = None
-            C = _cntr.Cntr(x, y, z.filled(), _mask)
-        self.Cntr = C
+        self._process_args(*args, **kwargs)
         self._process_levels()
 
         if self.colors is not None:
@@ -673,28 +688,23 @@
             kw['norm'] = norm
         cm.ScalarMappable.__init__(self, **kw) # sets self.cmap;
         self._process_colors()
+
+        self.allsegs, self.allkinds = self._get_allsegs_and_allkinds()
+
         if self.filled:
             if self.linewidths is not None:
                 warnings.warn('linewidths is ignored by contourf')
 
-            lowers = self._levels[:-1]
-            if self.zmin == lowers[0]:
-                # Include minimum values in lowest interval
-                lowers = lowers.copy() # so we don't change self._levels
-                if self.logscale:
-                    lowers[0] = 0.99 * self.zmin
-                else:
-                    lowers[0] -= 1
-            uppers = self._levels[1:]
+            # Lower and upper contour levels.
+            lowers, uppers = self._get_lowers_and_uppers()
 
-            for level, level_upper in zip(lowers, uppers):
-                nlist = C.trace(level, level_upper, nchunk = self.nchunk)
-                nseg = len(nlist)//2
-                segs = nlist[:nseg]
-                kinds = nlist[nseg:]
+            # Ensure allkinds can be zipped below.
+            if self.allkinds is None:
+                self.allkinds = [None]*len(self.allsegs)
 
+            for level, level_upper, segs, kinds in \
+                    zip(lowers, uppers, self.allsegs, self.allkinds):
                 paths = self._make_paths(segs, kinds)
-
                 # Default zorder taken from Collection
                 zorder = kwargs.get('zorder', 1)
                 col = collections.PathCollection(paths,
@@ -708,12 +718,8 @@
             tlinewidths = self._process_linewidths()
             self.tlinewidths = tlinewidths
             tlinestyles = self._process_linestyles()
-            for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles):
-                nlist = C.trace(level)
-                nseg = len(nlist)//2
-                segs = nlist[:nseg]
-                #kinds = nlist[nseg:]
-
+            for level, width, lstyle, segs in \
+                    zip(self.levels, tlinewidths, tlinestyles, self.allsegs):
                 # Default zorder taken from LineCollection
                 zorder = kwargs.get('zorder', 2)
                 col = collections.LineCollection(segs,
@@ -721,20 +727,81 @@
                                      linestyle = lstyle,
                                      alpha=self.alpha,
                                      zorder=zorder)
-
                 col.set_label('_nolegend_')
                 self.ax.add_collection(col, False)
                 self.collections.append(col)
         self.changed() # set the colors
 
-    def _make_paths(self, segs, kinds):
-        paths = []
-        for seg, kind in zip(segs, kinds):
-            paths.append(mpath.Path(seg, codes=kind))
-        return paths
+    def _process_args(self, *args, **kwargs):
+        """
+        Process args and kwargs; override in derived classes.
 
+        Must set self.levels, self.zmin and self.zmax, and update axes
+        limits.
+        """
+        self.levels = args[0]
+        self.allsegs = args[1]
+        self.allkinds = len(args) > 2 and args[2] or None
+        self.zmax = np.amax(self.levels)
+        self.zmin = np.amin(self.levels)
+        self._auto = False
 
+        # Check lengths of levels and allsegs.
+        if self.filled:
+            if len(self.allsegs) != len(self.levels)-1:
+                raise ValueError('must be one less number of segments as levels')
+        else:
+            if len(self.allsegs) != len(self.levels):
+                raise ValueError('must be same number of segments as levels')
 
+        # Check length of allkinds.
+        if self.allkinds is not None and len(self.allkinds) != len(self.allsegs):
+            raise ValueError('allkinds has different length to allsegs')
+
+        # Determine x,y bounds and update axes data limits.
+        havelimits = False
+        for segs in self.allsegs:
+            for seg in segs:
+                seg = np.asarray(seg)
+                if havelimits:
+                    min = np.minimum(min, seg.min(axis=0))
+                    max = np.maximum(max, seg.max(axis=0))
+                else:
+                    min = seg.min(axis=0)
+                    max = seg.max(axis=0)
+                    havelimits = True
+        if havelimits:
+            self.ax.update_datalim([min, max])
+            self.ax.autoscale_view()
+
+    def _get_allsegs_and_allkinds(self):
+        """
+        Override in derived classes to create and return allsegs and allkinds.
+        allkinds can be None.
+        """
+        return self.allsegs, self.allkinds
+
+    def _get_lowers_and_uppers(self):
+        """
+        Return (lowers,uppers) for filled contours.
+        """
+        lowers = self._levels[:-1]
+        if self.zmin == lowers[0]:
+            # Include minimum values in lowest interval
+            lowers = lowers.copy() # so we don't change self._levels
+            if self.logscale:
+                lowers[0] = 0.99 * self.zmin
+            else:
+                lowers[0] -= 1
+        uppers = self._levels[1:]
+        return (lowers, uppers)
+
+    def _make_paths(self, segs, kinds):
+        if kinds is not None:
+            return [mpath.Path(seg,codes=kind) for seg,kind in zip(segs,kinds)]
+        else:
+            return [mpath.Path(seg) for seg in segs]
+
     def changed(self):
         tcolors = [ (tuple(rgba),) for rgba in
                                 self.to_rgba(self.cvalues, alpha=self.alpha)]
@@ -750,7 +817,6 @@
         # add label colors
         cm.ScalarMappable.changed(self)
 
-
     def _autolev(self, z, N):
         '''
         Select contour levels to span the data.
@@ -778,101 +844,18 @@
         # For line contours, drop levels outside the data range.
         return lev[(lev > zmin) & (lev < zmax)]
 
-    def _initialize_x_y(self, z):
-        '''
-        Return X, Y arrays such that contour(Z) will match imshow(Z)
-        if origin is not None.
-        The center of pixel Z[i,j] depends on origin:
-        if origin is None, x = j, y = i;
-        if origin is 'lower', x = j + 0.5, y = i + 0.5;
-        if origin is 'upper', x = j + 0.5, y = Nrows - i - 0.5
-        If extent is not None, x and y will be scaled to match,
-        as in imshow.
-        If origin is None and extent is not None, then extent
-        will give the minimum and maximum values of x and y.
-        '''
-        if z.ndim != 2:
-            raise TypeError("Input must be a 2D array.")
-        else:
-            Ny, Nx = z.shape
-        if self.origin is None:  # Not for image-matching.
-            if self.extent is None:
-                return np.meshgrid(np.arange(Nx), np.arange(Ny))
-            else:
-                x0,x1,y0,y1 = self.extent
-                x = np.linspace(x0, x1, Nx)
-                y = np.linspace(y0, y1, Ny)
-                return np.meshgrid(x, y)
-        # Match image behavior:
-        if self.extent is None:
-            x0,x1,y0,y1 = (0, Nx, 0, Ny)
-        else:
-            x0,x1,y0,y1 = self.extent
-        dx = float(x1 - x0)/Nx
-        dy = float(y1 - y0)/Ny
-        x = x0 + (np.arange(Nx) + 0.5) * dx
-        y = y0 + (np.arange(Ny) + 0.5) * dy
-        if self.origin == 'upper':
-            y = y[::-1]
-        return np.meshgrid(x,y)
-
-    def _check_xyz(self, args, kwargs):
-        '''
-        For functions like contour, check that the dimensions
-        of the input arrays match; if x and y are 1D, convert
-        them to 2D using meshgrid.
-
-        Possible change: I think we should make and use an ArgumentError
-        Exception class (here and elsewhere).
-        '''
-        x, y = args[:2]
-        self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
-        x = self.ax.convert_xunits(x)
-        y = self.ax.convert_yunits(y)
-
-        x = np.asarray(x, dtype=np.float64)
-        y = np.asarray(y, dtype=np.float64)
-        z = ma.asarray(args[2], dtype=np.float64)
-        if z.ndim != 2:
-            raise TypeError("Input z must be a 2D array.")
-        else: Ny, Nx = z.shape
-        if x.shape == z.shape and y.shape == z.shape:
-            return x,y,z
-        if x.ndim != 1 or y.ndim != 1:
-            raise TypeError("Inputs x and y must be 1D or 2D.")
-        nx, = x.shape
-        ny, = y.shape
-        if nx != Nx or ny != Ny:
-            raise TypeError("Length of x must be number of columns in z,\n" +
-                            "and length of y must be number of rows.")
-        x,y = np.meshgrid(x,y)
-        return x,y,z
-
-
-    def _contour_args(self, args, kwargs):
+    def _contour_level_args(self, z, args):
+        """
+        Determine the contour levels and store in self.levels.
+        """
         if self.filled: fn = 'contourf'
         else:           fn = 'contour'
-        Nargs = len(args)
-        if Nargs <= 2:
-            z = ma.asarray(args[0], dtype=np.float64)
-            x, y = self._initialize_x_y(z)
-        elif Nargs <=4:
-            x,y,z = self._check_xyz(args[:3], kwargs)
-        else:
-            raise TypeError("Too many arguments to %s; see help(%s)" % (fn,fn))
-        z = ma.masked_invalid(z, copy=False)
-        self.zmax = ma.maximum(z)
-        self.zmin = ma.minimum(z)
-        if self.logscale and self.zmin <= 0:
-            z = ma.masked_where(z <= 0, z)
-            warnings.warn('Log scale: values of z <=0 have been masked')
-            self.zmin = z.min()
         self._auto = False
         if self.levels is None:
-            if Nargs == 1 or Nargs == 3:
+            if len(args) == 0:
                 lev = self._autolev(z, 7)
-            else:   # 2 or 4 args
-                level_arg = args[-1]
+            else:
+                level_arg = args[0]
                 try:
                     if type(level_arg) == int:
                         lev = self._autolev(z, level_arg)
@@ -884,7 +867,6 @@
             if self.filled and len(lev) < 2:
                 raise ValueError("Filled contours require at least 2 levels.")
             self.levels = lev
-        return (x, y, z)
 
     def _process_levels(self):
         self._levels = list(self.levels)
@@ -907,7 +889,6 @@
             if self.extend in ('both', 'max'):
                 self.layers[-1] = 0.5 * (self.vmax + self._levels[-2])
 
-
     def _process_colors(self):
         """
         Color argument processing for contouring.
@@ -989,6 +970,241 @@
         self.alpha = alpha
         self.changed()
 
+    def find_nearest_contour( self, x, y, indices=None, pixel=True ):
+        """
+        Finds contour that is closest to a point.  Defaults to
+        measuring distance in pixels (screen space - useful for manual
+        contour labeling), but this can be controlled via a keyword
+        argument.
+
+        Returns a tuple containing the contour, segment, index of
+        segment, x & y of segment point and distance to minimum point.
+
+        Call signature::
+
+          conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour(
+                     self, x, y, indices=None, pixel=True )
+
+        Optional keyword arguments::
+
+        *indices*:
+           Indexes of contour levels to consider when looking for
+           nearest point.  Defaults to using all levels.
+
+        *pixel*:
+           If *True*, measure distance in pixel space, if not, measure
+           distance in axes space.  Defaults to *True*.
+
+        """
+
+        # This function uses a method that is probably quite
+        # inefficient based on converting each contour segment to
+        # pixel coordinates and then comparing the given point to
+        # those coordinates for each contour.  This will probably be
+        # quite slow for complex contours, but for normal use it works
+        # sufficiently well that the time is not noticeable.
+        # Nonetheless, improvements could probably be made.
+
+        if indices==None:
+            indices = range(len(self.levels))
+
+        dmin = 1e10
+        conmin = None
+        segmin = None
+        xmin = None
+        ymin = None
+
+        for icon in indices:
+            con = self.collections[icon]
+            paths = con.get_paths()
+            for segNum, linepath in enumerate(paths):
+                lc = linepath.vertices
+
+                # transfer all data points to screen coordinates if desired
+                if pixel:
+                    lc = self.ax.transData.transform(lc)
+
+                ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
+                d = min( ds )
+                if d < dmin:
+                    dmin = d
+                    conmin = icon
+                    segmin = segNum
+                    imin = mpl.mlab.find( ds == d )[0]
+                    xmin = lc[imin,0]
+                    ymin = lc[imin,1]
+
+        return (conmin,segmin,imin,xmin,ymin,dmin)
+
+
+class QuadContourSet(ContourSet):
+    """
+    Create and store a set of contour lines or filled regions.
+
+    User-callable method: clabel
+
+    Useful attributes:
+      ax:
+        the axes object in which the contours are drawn
+      collections:
+        a silent_list of LineCollections or PolyCollections
+      levels:
+        contour levels
+      layers:
+        same as levels for line contours; half-way between
+        levels for filled contours.  See _process_colors method.
+    """
+    def __init__(self, ax, *args, **kwargs):
+        """
+        Calculate and draw contour lines or filled regions, depending
+        on whether keyword arg 'filled' is False (default) or True.
+
+        The first argument of the initializer must be an axes
+        object.  The remaining arguments and keyword arguments
+        are described in QuadContourSet.contour_doc.
+        """
+        ContourSet.__init__(self, ax, *args, **kwargs)
+
+    def _process_args(self, *args, **kwargs):
+        """
+        Process args and kwargs.
+        """
+        if isinstance(args[0], QuadContourSet):
+            C = args[0].Cntr
+            if self.levels is None:
+                self.levels = args[0].levels
+        else:
+            x, y, z = self._contour_args(args, kwargs)
+
+            x0 = ma.minimum(x)
+            x1 = ma.maximum(x)
+            y0 = ma.minimum(y)
+            y1 = ma.maximum(y)
+            self.ax.update_datalim([(x0,y0), (x1,y1)])
+            self.ax.autoscale_view()
+            _mask = ma.getmask(z)
+            if _mask is ma.nomask:
+                _mask = None
+            C = _cntr.Cntr(x, y, z.filled(), _mask)
+        self.Cntr = C
+
+    def _get_allsegs_and_allkinds(self):
+        """
+        Create and return allsegs and allkinds by calling underlying C code.
+        """
+        allsegs = []
+        if self.filled:
+            lowers, uppers = self._get_lowers_and_uppers()
+            allkinds = []
+            for level, level_upper in zip(lowers, uppers):
+                nlist = self.Cntr.trace(level, level_upper, nchunk = self.nchunk)
+                nseg = len(nlist)//2
+                segs = nlist[:nseg]
+                kinds = nlist[nseg:]
+                allsegs.append(segs)
+                allkinds.append(kinds)
+        else:
+            allkinds = None
+            for level in self.levels:
+                nlist = self.Cntr.trace(level)
+                nseg = len(nlist)//2
+                segs = nlist[:nseg]
+                allsegs.append(segs)
+        return allsegs, allkinds
+
+    def _contour_args(self, args, kwargs):
+        if self.filled: fn = 'contourf'
+        else:           fn = 'contour'
+        Nargs = len(args)
+        if Nargs <= 2:
+            z = ma.asarray(args[0], dtype=np.float64)
+            x, y = self._initialize_x_y(z)
+            args = args[1:]
+        elif Nargs <=4:
+            x,y,z = self._check_xyz(args[:3], kwargs)
+            args = args[3:]
+        else:
+            raise TypeError("Too many arguments to %s; see help(%s)" % (fn,fn))
+        z = ma.masked_invalid(z, copy=False)
+        self.zmax = ma.maximum(z)
+        self.zmin = ma.minimum(z)
+        if self.logscale and self.zmin <= 0:
+            z = ma.masked_where(z <= 0, z)
+            warnings.warn('Log scale: values of z <= 0 have been masked')
+            self.zmin = z.min()
+        self._contour_level_args(z, args)
+        return (x, y, z)
+
+    def _check_xyz(self, args, kwargs):
+        '''
+        For functions like contour, check that the dimensions
+        of the input arrays match; if x and y are 1D, convert
+        them to 2D using meshgrid.
+
+        Possible change: I think we should make and use an ArgumentError
+        Exception class (here and elsewhere).
+        '''
+        x, y = args[:2]
+        self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
+        x = self.ax.convert_xunits(x)
+        y = self.ax.convert_yunits(y)
+
+        x = np.asarray(x, dtype=np.float64)
+        y = np.asarray(y, dtype=np.float64)
+        z = ma.asarray(args[2], dtype=np.float64)
+        if z.ndim != 2:
+            raise TypeError("Input z must be a 2D array.")
+        else: Ny, Nx = z.shape
+        if x.shape == z.shape and y.shape == z.shape:
+            return x,y,z
+        if x.ndim != 1 or y.ndim != 1:
+            raise TypeError("Inputs x and y must be 1D or 2D.")
+        nx, = x.shape
+        ny, = y.shape
+        if nx != Nx or ny != Ny:
+            raise TypeError("Length of x must be number of columns in z,\n" +
+                            "and length of y must be number of rows.")
+        x,y = np.meshgrid(x,y)
+        return x,y,z
+
+    def _initialize_x_y(self, z):
+        '''
+        Return X, Y arrays such that contour(Z) will match imshow(Z)
+        if origin is not None.
+        The center of pixel Z[i,j] depends on origin:
+        if origin is None, x = j, y = i;
+        if origin is 'lower', x = j + 0.5, y = i + 0.5;
+        if origin is 'upper', x = j + 0.5, y = Nrows - i - 0.5
+        If extent is not None, x and y will be scaled to match,
+        as in imshow.
+        If origin is None and extent is not None, then extent
+        will give the minimum and maximum values of x and y.
+        '''
+        if z.ndim != 2:
+            raise TypeError("Input must be a 2D array.")
+        else:
+            Ny, Nx = z.shape
+        if self.origin is None:  # Not for image-matching.
+            if self.extent is None:
+                return np.meshgrid(np.arange(Nx), np.arange(Ny))
+            else:
+                x0,x1,y0,y1 = self.extent
+                x = np.linspace(x0, x1, Nx)
+                y = np.linspace(y0, y1, Ny)
+                return np.meshgrid(x, y)
+        # Match image behavior:
+        if self.extent is None:
+            x0,x1,y0,y1 = (0, Nx, 0, Ny)
+        else:
+            x0,x1,y0,y1 = self.extent
+        dx = float(x1 - x0)/Nx
+        dy = float(y1 - y0)/Ny
+        x = x0 + (np.arange(Nx) + 0.5) * dx
+        y = y0 + (np.arange(Ny) + 0.5) * dy
+        if self.origin == 'upper':
+            y = y[::-1]
+        return np.meshgrid(x,y)
+
     contour_doc = """
         :func:`~matplotlib.pyplot.contour` and
         :func:`~matplotlib.pyplot.contourf` draw contour lines and
@@ -1047,7 +1263,7 @@
         handle internal masked regions correctly.
 
         ``C = contour(...)`` returns a
-        :class:`~matplotlib.contour.ContourSet` object.
+        :class:`~matplotlib.contour.QuadContourSet` object.
 
         Optional keyword arguments:
 
@@ -1170,69 +1386,3 @@
 
         .. plot:: mpl_examples/pylab_examples/contourf_demo.py
         """
-
-    def find_nearest_contour( self, x, y, indices=None, pixel=True ):
-        """
-        Finds contour that is closest to a point.  Defaults to
-        measuring distance in pixels (screen space - useful for manual
-        contour labeling), but this can be controlled via a keyword
-        argument.
-
-        Returns a tuple containing the contour, segment, index of
-        segment, x & y of segment point and distance to minimum point.
-
-        Call signature::
-
-          conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour(
-                     self, x, y, indices=None, pixel=True )
-
-        Optional keyword arguments::
-
-        *indices*:
-           Indexes of contour levels to consider when looking for
-           nearest point.  Defaults to using all levels.
-
-        *pixel*:
-           If *True*, measure distance in pixel space, if not, measure
-           distance in axes space.  Defaults to *True*.
-
-        """
-
-        # This function uses a method that is probably quite
-        # inefficient based on converting each contour segment to
-        # pixel coordinates and then comparing the given point to
-        # those coordinates for each contour.  This will probably be
-        # quite slow for complex contours, but for normal use it works
-        # sufficiently well that the time is not noticeable.
-        # Nonetheless, improvements could probably be made.
-
-        if indices==None:
-            indices = range(len(self.levels))
-
-        dmin = 1e10
-        conmin = None
-        segmin = None
-        xmin = None
-        ymin = None
-
-        for icon in indices:
-            con = self.collections[icon]
-            paths = con.get_paths()
-            for segNum, linepath in enumerate(paths):
-                lc = linepath.vertices
-
-                # transfer all data points to screen coordinates if desired
-                if pixel:
-                    lc = self.ax.transData.transform(lc)
-
-                ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
-                d = min( ds )
-                if d < dmin:
-                    dmin = d
-                    conmin = icon
-                    segmin = segNum
-                    imin = mpl.mlab.find( ds == d )[0]
-                    xmin = lc[imin,0]
-                    ymin = lc[imin,1]
-
-        return (conmin,segmin,imin,xmin,ymin,dmin)
Index: lib/matplotlib/axes.py
===================================================================
--- lib/matplotlib/axes.py	(revision 8226)
+++ lib/matplotlib/axes.py	(working copy)
@@ -6896,14 +6896,14 @@
     def contour(self, *args, **kwargs):
         if not self._hold: self.cla()
         kwargs['filled'] = False
-        return mcontour.ContourSet(self, *args, **kwargs)
-    contour.__doc__ = mcontour.ContourSet.contour_doc
+        return mcontour.QuadContourSet(self, *args, **kwargs)
+    contour.__doc__ = mcontour.QuadContourSet.contour_doc
 
     def contourf(self, *args, **kwargs):
         if not self._hold: self.cla()
         kwargs['filled'] = True
-        return mcontour.ContourSet(self, *args, **kwargs)
-    contourf.__doc__ = mcontour.ContourSet.contour_doc
+        return mcontour.QuadContourSet(self, *args, **kwargs)
+    contourf.__doc__ = mcontour.QuadContourSet.contour_doc
 
     def clabel(self, CS, *args, **kwargs):
         return CS.clabel(*args, **kwargs)
Index: examples/misc/contour_manual.py
===================================================================
--- examples/misc/contour_manual.py	(revision 0)
+++ examples/misc/contour_manual.py	(revision 0)
@@ -0,0 +1,50 @@
+"""
+Example of displaying your own contour lines and polygons using ContourSet.
+"""
+import matplotlib.pyplot as plt
+from matplotlib.contour import ContourSet
+import matplotlib.cm as cm
+
+# Contour lines for each level are a list/tuple of polygons.
+lines0 = [ [[0,0],[0,4]] ]
+lines1 = [ [[2,0],[1,2],[1,3]] ]
+lines2 = [ [[3,0],[3,2]], [[3,3],[3,4]] ]  # Note two lines.
+
+# Filled contours between two levels are also a list/tuple of polygons.
+# Points can be ordered clockwise or anticlockwise.
+filled01 = [ [[0,0],[0,4],[1,3],[1,2],[2,0]] ]
+filled12 = [ [[2,0],[3,0],[3,2],[1,3],[1,2]],   # Note two polygons.
+             [[1,4],[3,4],[3,3]] ]
+
+
+plt.figure()
+
+# Filled contours using filled=True.
+cs = ContourSet(plt.gca(), [0,1,2], [filled01, filled12], filled=True, cmap=cm.bone)
+cbar = plt.colorbar(cs)
+
+# Contour lines (non-filled).
+lines = ContourSet(plt.gca(), [0,1,2], [lines0, lines1, lines2], cmap=cm.cool,
+                   linewidths=3)
+cbar.add_lines(lines)
+
+plt.axis([-0.5, 3.5, -0.5, 4.5])
+plt.title('User-specified contours')
+
+
+
+# Multiple filled contour lines can be specified in a single list of polygon
+# vertices along with a list of vertex kinds (code types) as described in the
+# Path class.  This is particularly useful for polygons with holes.
+# Here a code type of 1 is a MOVETO, and 2 is a LINETO.
+
+plt.figure()
+filled01 = [ [[0,0],[3,0],[3,3],[0,3],[1,1],[1,2],[2,2],[2,1]] ]
+kinds01  = [ [1,2,2,2,1,2,2,2] ]
+cs = ContourSet(plt.gca(), [0,1], [filled01], [kinds01], filled=True)
+cbar = plt.colorbar(cs)
+
+plt.axis([-0.5, 3.5, -0.5, 3.5])
+plt.title('User specified filled contours with holes')
+
+plt.show()

Property changes on: examples/misc/contour_manual.py
___________________________________________________________________
Added: svn:keywords
   + Id

