def generate_rr(self, set_nbins=None, logbins=True, min_sep=0.01, 
                    force_n_randoms=None, save_to=None, n_chunks=1):
        #Do random-random counts over the entire field.  If set_nbins is declared,
        #generate_rr will not go looking for the correlation functions so that the
        #RR counts for the IC calculation and the CF calculation can be done in parallel.
 
        #Figure out how many randoms we need.  This was calculated by playing with
        #the number of randoms in the GOODS-S field and seeing when the RR counts converged
        #to the "way too many" curve.  27860 per 1.43e-5 steradians was what I settled on.
        #If there's a forced number, it will ignore my estimate.
        #  Amendment 4/15- this minimum number seems to be somewhat too small for fields that 
        #                  aren't as smooth as GOODS-S, so I'm multiplying it by 5.  This looks ok.
        #  Amendment 8/15- added the capability to do this in several chunks.
        
        if force_n_randoms is None:
            surface_density_required = 27860.*5./1.43e-5
            area = self._image_mask.masked_area_solid_angle()
            number_needed = surface_density_required * area
        else:
            number_needed=force_n_randoms

        #If we're doing more than one chunk, divide the number we need into n_chunks chunks
        if n_chunks > 1:
            number_needed = np.ceil(float(number_needed)/n_chunks).astype(int)
        total_number = number_needed * n_chunks
        print "total number: ",  total_number
        print "number per iteration: ", number_needed
        print "number of chunks: ", n_chunks

        #Range of separations to make bins over
        min_ra = self._ra[self._use].min()
        min_dec = self._dec[self._use].min()
        max_ra = self._ra[self._use].max()
        max_dec = self._dec[self._use].max()
        max_sep=misc.ang_sep(min_ra, min_dec, max_ra, max_dec,
                           radians_in=False, radians_out=False)

        #Choose how many bins
        if set_nbins is None:
            #Get our theta bin info from the CF if we can.  Error if we can't
            if self._theta_bins is None:
                raise ValueError("AngularCatalog.generate_rr says: I need"
                                " either a set number of bins (set_nbins=N)"
                                " or thetas from a CF to extrapolate. "
                                " You have given me neither.")
            centers, edges = self._cfs[name].get_thetas(unit='degrees')
            nbins= np.ceil( len(centers) * 2. * max_sep/edges.max())
        else:
            nbins=set_nbins

        #Make the bins
        rr_theta_bins = binclass.ThetaBins(min_sep, max_sep, nbins,
                                           unit='d', logbins=logbins)
        use_centers, use_theta_bins = rr_theta_bins.get_thetas(unit='degrees')

        #Do the loop
        G_p=np.zeros(nbins)
        rr_counts=np.zeros(nbins)
        for n_i in np.arange(n_chunks):
            print "doing chunk #", n_i
            #Remake the random sample so we're sure we have the right oversample factor            
            self.generate_random_sample(masked=True, make_exactly=number_needed)
        
            #Code snippet shamelessly copied from astroML.correlations
            xyz_data = corr.ra_dec_to_xyz(self._ra_random,
                                         self._dec_random)
            data_R = np.asarray(xyz_data, order='F').T
            bins = corr.angular_dist_to_euclidean_dist(use_theta_bins)
            Nbins = len(bins) - 1
            counts_RR = np.zeros(Nbins + 1)
            for i in range(Nbins + 1):
                counts_RR[i] = np.sum(self._random_tree.query_radius(data_R, bins[i],
                                                                            count_only=True))
            rr = np.diff(counts_RR)
            #Landy and Szalay define G_p(theta) as <N_p(theta)>/(n(n-1)/2)
            G_p += rr/(number_needed*(number_needed-1)) 
            rr_counts += rr

        print "Dividing out the theta bin sizes and number of chunks"
        
        #I divide out the bin width because just using the method
        #that L&S detail gives you a {G_p,i} with the property that
        #Sum[G_p,i]=1.  This is not equivalent to Integral[G_p d(theta)]=1,
        #which is what they assume everywhere else.
        #Dividing out the bin width gives you that and lets you pretend
        #G_p is a continuous but chunky-looking function.
        G_p /= np.diff(use_theta_bins)                    
        G_p /= n_chunks                                   
        self._rr_ngals=[total_number, n_chunks]
        self._Gp = gpclass.Gp(min_sep, max_sep, nbins, G_p, total_number,
                              n_chunks, logbins=logbins, unit='d',
                              RR=rr_counts)

        if save_to is not None:
            self.save_gp(save_to)
    def subdivide_mask(self, n_shortside=3, n_longside=4, preview=False,
                       rotation_angle=None, padding=None, only_show=None,
                       save_plot=None):
        """
        Subdivide mask takes the image mask, draws a rectangle around the
        valid region of the mask, rotated to be as small as possible, and
        subdivides that rectangle.  The rotation angle of the box can be
        set manually and space can be trimmed or added from the sides of
        the box.

        Parameters
        ----------
        n_shortside : integer (optional)
            The number of cells along the short side of the rectangle.
            Default is 3.
            
        n_longside : integer (optional)
            The number of cells along the long side of the rectangle.
            Default is 4.
            
        preview : bool (optional)
            Should the mask show you what this set of parameters looks like
            but not store the results?  If preview == True, either a plot
            will be shown on your screen (no value given for save_plot) or
            saved to a file (save_plot specified).  The image mask object
            will not keep the division information.  If preview == False,
            which is the default, the values will be stored and a plot will
            only be made if save_plot is specified.
            
        rotation_angle : scalar (optional)
            Fixes the rotation angle that the mask's bounding box will be
            defined at with respect to the XY coordinate system of the
            mask.  By default, the routine will choose the integer angle in
            degrees which minimizes the area of the bounding box.
            
        padding : 4 element array-like (optional)
            How many pixels extra to allow in the rotated coordinates of
            the bounding box.  The order is [bottom, top, left, right].
            Positive padding corresponds to moving the edges outwards and
            leaving extra room.  Negative padding will move the bounding
            box inward and cut off part of the mask.
            
        only_show : integer (optional)
            If you only want to see the random points that fall into one of
            the cells in the subdivided mask, you set only_show to that
            cell number.  This will only matter if you have preview=True
            or have specified save_plot.
            
        save_plot : string (optional)
            Name with path from '/' of the file where you would like the
            plot of the subdivided mask saved.  If only_show is set to an
            integer that corresponds to a cell number, only the points in
            that cell will be shown.
        """
        
        #Start by putting down a bunch of randoms.
        ra, dec, __ = self.generate_random_sample(5.e4)
        x1, y1=self.ra_dec_to_xy(ra, dec)

        #Set the padding on each side
        if padding:
            try:
                pad_bottom, pad_top, pad_left, pad_right=padding
            except:
                #If we can't unpack the padding, either raise an
                #informative error (if we're doing the subdivision
                #permanently) or just a warning if we're only previewing
                says_str = "subdivide_mask says: "
                message_str = ("You have given me something I can't use "
                               "for padding.  Padding must be a 4-element "
                               "1D array in the format [bottom, top, left,"
                               " right].")
                if preview == True:
                    print (says_str + "WARNING!  " + message_str +
                           "  No padding used this time")
                    pad_bottom, pad_top, pad_left, pad_right=[0,0,0,0]
                else:
                    raise ValueError(says_str + "ERROR!  " + message_str)
        else:
            pad_bottom, pad_top, pad_left, pad_right=[0,0,0,0]
        
        #If we don't have an already chosen angle, choose a bunch of angles
        #and transform the coordinates to rotated systems and get the areas
        #of the rectangle enclosing all the data points at this angle. Take
        #The angle with the minimum area for the enclosing rectangle.
        if rotation_angle is None:
            thetas=np.radians(np.arange(90, dtype=np.float))
            areas=[]
            corners=[]
            for th in thetas:
                x2, y2= misc.rotate_coords(x1, y1, th)
                #Don't take padding into account to determine the angle.
                x2min=x2.min()
                x2max=x2.max()
                y2min=y2.min()
                y2max=y2.max()
                areas.append((x2.max()-x2.min()) * (y2.max()-y2.min()))

            areas=np.asarray(areas)
            which_theta=np.where(areas==areas.min())[0][0]
            use_theta=thetas[which_theta]
        #Else, use the given angle
        else:
            use_theta=np.radians(rotation_angle)

        #Define the edges of the regions
        x2, y2= misc.rotate_coords(x1, y1, use_theta)
        x2min=x2.min() - pad_left
        x2max=x2.max() + pad_right
        y2min=y2.min() - pad_bottom
        y2max=y2.max() + pad_top

        #Figure out the x2 and y2 bin divisions
        if (x2max-x2min) < (y2max-y2min):
            nx=n_shortside
            ny=n_longside
        else:
            ny=n_shortside
            nx=n_longside

        x2edges = np.linspace(x2min, x2max, nx+1)
        y2edges = np.linspace(y2min, y2max, ny+1)

        #-----------------#
        #- Make the plot -#
        #-----------------#
        if preview or save_plot:
            #Figure out what subregions we have
            subregions=self.return_subregions(ra, dec, theta=use_theta,
                                              rot_xedges=x2edges,
                                              rot_yedges=y2edges)
            outside = subregions == -1
            inside= np.invert(outside)
            if only_show is not None:
                this_box = subregions==only_show
                inside = inside & this_box

            #Make a figure and plot the random points
            fig=plt.figure()
            ax=fig.add_subplot(111)
            ax.scatter(x1[outside], y1[outside], c='LightGray')
            ax.scatter(x1[inside], y1[inside], c='Blue')  
                      
            #Plot the vertical lines
            for ix in range(nx+1):
                x2=[x2edges[ix], x2edges[ix]]
                y2=[y2min, y2max]
                x1, y1=misc.rotate_coords(x2, y2, -use_theta)
                ax.plot(x1, y1, color='Red', lw=2)
            #Plot the horizontal lines
            for iy in range(ny+1):
                x2=[x2min, x2max]
                y2=[y2edges[iy], y2edges[iy]]
                x1, y1=misc.rotate_coords(x2, y2, -use_theta)
                ax.plot(x1, y1, color='Red', lw=2)

            #Figure out the dimensions of the boxes in angular space
            x2=[x2edges[0], x2edges[0], x2edges[1]]
            y2=[y2edges[0], y2edges[1], y2edges[0]]
            ra_box, dec_box=self.xy_to_ra_dec(x2, y2)
            y_side=misc.ang_sep(ra_box[0], dec_box[0], ra_box[1], dec_box[1],
                               radians_in=False, radians_out=False) * 3600
            x_side=misc.ang_sep(ra_box[0], dec_box[0], ra_box[2], dec_box[2],
                               radians_in=False, radians_out=False) * 3600

            #Print out the parameters
            ax.text(.05, .95, "theta= "+str(np.degrees(use_theta))[0:5],
                    transform=ax.transAxes, fontsize=8)
            ax.text(.05, .925, "padding="+str(padding),
                    transform=ax.transAxes, fontsize=8)
            ax.text(.05, .9, "n_longside="+str(n_longside),
                    transform=ax.transAxes, fontsize=8)
            ax.text(.05, .875, "n_shortside="+str(n_shortside),
                    transform=ax.transAxes, fontsize=8)
            ax.text(.5, .05, ("box size: "+str(x_side)[0:5]+" by "+
                              str(y_side)[0:5]+" arcsec"),
                    transform=ax.transAxes, fontsize=8)

            #Label the subregions
            y_label_coord=.85
            avg_ngals=float(len(ra[np.invert(outside)]))/(nx*ny)
            ax.text(0.8, 0.95, "N_bin/N_avg", transform=ax.transAxes,
                    fontsize=12)
            ax.text(0.8, 0.9, "outside-> "+str(float(len(ra[outside]))/avg_ngals)[0:4],
                    transform=ax.transAxes, fontsize=9)
            for ix in range(nx):
                for iy in range(ny):
                    #What bin number is this?
                    bin_number= nx*iy + ix
                    #Where's the center of the box?
                    text_x2=(x2edges[ix] + x2edges[ix+1])/2.
                    text_y2=(y2edges[iy] + y2edges[iy+1])/2.
                    text_x1, text_y1=misc.rotate_coords(text_x2, text_y2,
                                                        -use_theta)
                    #Print the bin number at the center of the box
                    ax.text(text_x1, text_y1, str(bin_number), fontsize=20,
                            color='Lime', horizontalalignment='center',
                            verticalalignment='center')

                    #Print the number of galaxies in the upper right corner
                    thisbin= subregions==bin_number
                    n_thisbin= float(len(ra[thisbin]))
                    print ("bin "+str(bin_number)+" has "+str(n_thisbin)+
                           " randoms in it")
                    display_string=('bin '+str(bin_number)+'-> '+
                                    str(n_thisbin/avg_ngals)[0:4])
                    ax.text(0.85, y_label_coord, display_string,
                            transform=ax.transAxes, fontsize=9)
                    y_label_coord-=0.05

            if save_plot:
                plt.savefig(save_plot, bbox_inches='tight')
                plt.close()
            else:
                plt.show()

        #If we want to store the information, do so
        if not preview:
            #Store the subregion information
            self.set_subregions(use_theta, x2edges, y2edges)