import numpy as np
from matplotlib import pyplot as plt


def scatter_contour(x, y,
                    levels=10,
                    threshold=100,
                    log_counts=False,
                    histogram2d_args={},
                    plot_args={},
                    contour_args={},
                    ax=None):
    """Scatter plot with contour over dense regions

    Parameters
    ----------
    x, y : arrays
        x and y data for the contour plot
    levels : integer or array (optional, default=10)
        number of contour levels, or array of contour levels
    threshold : float (default=100)
        number of points per 2D bin at which to begin drawing contours
    log_counts :boolean (optional)
        if True, contour levels are the base-10 logarithm of bin counts.
    histogram2d_args : dict
        keyword arguments passed to numpy.histogram2d
        see doc string of numpy.histogram2d for more information
    plot_args : dict
        keyword arguments passed to pylab.scatter
        see doc string of pylab.scatter for more information
    contourf_args : dict
        keyword arguments passed to pylab.contourf
        see doc string of pylab.contourf for more information
    ax : pylab.Axes instance
        the axes on which to plot.  If not specified, the current
        axes will be used
    """
    if ax is None:
        ax = plt.gca()

    H, xbins, ybins = np.histogram2d(x, y, **histogram2d_args)

    Nx = len(xbins)
    Ny = len(ybins)

    if log_counts:
        H = np.log10(1 + H)
        threshold = np.log10(1 + threshold)

    levels = np.asarray(levels)

    if levels.size == 1:
        levels = np.linspace(threshold, H.max(), levels)

    extent = [xbins[0], xbins[-1], ybins[0], ybins[-1]]

    i_min = np.argmin(levels)

    # draw a zero-width line: this gives us the outer polygon to
    # reduce the number of points we draw
    # somewhat hackish... we could probably get the same info from
    # the filled contour below.
    outline = ax.contour(H.T, levels[i_min:i_min + 1],
                         linewidths=0, extent=extent)

    ax.contourf(H.T, levels, extent=extent, **contour_args)
    X = np.hstack([x[:, None], y[:, None]])

    if len(outline.allsegs[0]) > 0:
        outer_poly = outline.allsegs[0][0]
        try:
            # this works in newer matplotlib versions
            from matplotlib.path import Path
            points_inside = Path(outer_poly).contains_points(X)
        except:
            # this works in older matplotlib versions
            import matplotlib.nxutils as nx
            points_inside = nx.points_inside_poly(X, outer_poly)

        Xplot = X[~points_inside]
    else:
        Xplot = X

    ax.plot(Xplot[:, 0], Xplot[:, 1], zorder=1, **plot_args)

@@ -214,26 +214,28 @@
 gram2d_args=
-%7B%7D
+None
 ,%0A          
@@ -250,26 +250,28 @@
   plot_args=
-%7B%7D
+None
 ,%0A          
@@ -297,10 +297,53 @@
 rgs=
-%7B%7D
+None,%0A                    filled_contour=True
 ,%0A  
@@ -1047,28 +1047,92 @@
 sed to p
-ylab.scatter
+lt.plot.  By default it will use%0A        dict(marker='.', linestyle='none').
 %0A       
@@ -1156,23 +1156,20 @@
 f pylab.
-scatter
+plot
  for mor
@@ -1193,17 +1193,16 @@
  contour
-f
 _args : 
@@ -1243,20 +1243,18 @@
 sed to p
-ylab
+lt
 .contour
@@ -1254,16 +1254,31 @@
 contourf
+ or plt.contour
 %0A       
@@ -1328,24 +1328,130 @@
 information%0A
+    filled_contour : bool%0A        If True (default) use filled contours. Otherwise, use contour outlines.%0A
     ax : pyl
@@ -1567,16 +1567,350 @@
     %22%22%22%0A
+    x = np.asarray(x)%0A    y = np.asarray(y)%0A%0A    default_plot_args = dict(marker='.', linestyle='none')%0A%0A    if plot_args is not None:%0A        default_plot_args.update(plot_args)%0A    plot_args = default_plot_args%0A%0A    if histogram2d_args is None:%0A        histogram2d_args = %7B%7D%0A%0A    if contour_args is None:%0A        contour_args = %7B%7D%0A%0A
     if a
@@ -2530,21 +2530,19 @@
  # the f
-i
+u
 ll
-ed
  contour
@@ -2542,16 +2542,21 @@
 contour 
+plot 
 below.%0A 
@@ -2664,16 +2664,43 @@
 xtent)%0A%0A
+    if filled_contour:%0A    
     ax.c
@@ -2747,24 +2747,98 @@
 ntour_args)%0A
+    else:%0A        ax.contour(H.T, levels, extent=extent, **contour_args)%0A%0A
     X = np.h

update scatter_contour defaults