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)