def visualizeHealPixMap(theMap, nest=True, title="map", norm=None, vmin=None, vmax=None, cmap=plt.cm.hot_r): from matplotlib.collections import PolyCollection from matplotlib.colors import Normalize nside = hp.npix2nside(theMap.size) mapValue = theMap[theMap != hp.UNSEEN] indices = np.arange(theMap.size) seenInds = indices[theMap != hp.UNSEEN] print "Building polygons from HEALPixel map." vertices = np.zeros( (seenInds.size, 4, 2) ) print "Building polygons for "+str(seenInds.size)+" HEALPixels." for HPixel,i in zip(seenInds,xrange(seenInds.size)): corners = hp.vec2ang( np.transpose(hp.boundaries(nside,HPixel,nest=nest) ) ) # HEALPix insists on using theta/phi; we in astronomy like to use ra/dec. vertices[i,:,0] = corners[1] *180./np.pi vertices[i,:,1] = 90.0 - corners[0] * 180/np.pi fig, ax = plt.subplots(figsize=(12,12)) #coll = PolyCollection(vertices, array = mapValue, cmap = plt.cm.seismic, edgecolors='none') coll = PolyCollection(vertices, array=mapValue, cmap=cmap, edgecolors='none') coll.set_clim(vmin=vmin, vmax=vmax) ax.add_collection(coll) ax.set_title(title) ax.autoscale_view() fig.colorbar(coll,ax=ax) #ax.set_ylim([-60.2, -43]) print "Writing to file: "+title+".png" fig.savefig(title+".png",format="png")
def GetHealPixRectangles(nside, dbrange, nest): hpindex = np.arange(hp.nside2npix(nside)) vec_corners = hp.boundaries(nside, hpindex, nest=nest) vec_corners = np.transpose(vec_corners, (0,2,1)) vec_corners = np.reshape(vec_corners, (vec_corners.shape[0]*vec_corners.shape[1], vec_corners.shape[2])) theta_corners, phi_corners = hp.vec2ang(vec_corners) theta_corners = np.reshape(theta_corners, (theta_corners.shape[0]/4, 4)) phi_corners = np.reshape(phi_corners, (phi_corners.shape[0]/4, 4)) ra_corners = np.degrees(phi_corners) dec_corners = 90.0 - np.degrees(theta_corners) rainside = ( (ra_corners > dbrange[0]) & (ra_corners < dbrange[1]) ) rakeep = np.sum(rainside, axis=-1) decinside = ( (dec_corners > dbrange[2]) & (dec_corners < dbrange[3]) ) deckeep = np.sum(decinside, axis=-1) keep = ( (rakeep > 0) & (deckeep > 0) ) ra_corners, dec_corners, hpindex = Cut(ra_corners, dec_corners, hpindex, cut=keep) ramin = np.amin(ra_corners, axis=-1) ramax = np.amax(ra_corners, axis=-1) decmin = np.amin(dec_corners, axis=-1) decmax = np.amax(dec_corners, axis=-1) return ramin, ramax, decmin, decmax, hpindex
def write_reg(self, filename): """ Write a ds9 region file that represents this region as a set of diamonds. :param filename: file to write :return: None """ with open(filename, 'w') as out: for d in xrange(1, self.maxdepth + 1): for p in self.pixeldict[d]: line = "fk5; polygon(" #the following int() gets around some problems with np.int64 that exist prior to numpy v 1.8.1 vectors = zip( *hp.boundaries(2**d, int(p), step=1, nest=True)) positions = [] for sky in self.vec2sky(np.array(vectors), degrees=True): ra, dec = sky pos = SkyCoord(ra / 15, dec, unit=(u.degree, u.degree)) positions.append(pos.ra.to_string(sep=':', precision=2)) positions.append( pos.dec.to_string(sep=':', precision=2)) line += ','.join(positions) line += ")" print >> out, line return
def get_vertices(m): m = np.copy(m) top_npix = len(m) top_nside = hp.npix2nside(top_npix) top_order = int(np.log2(top_nside)) for order in range(top_order + 1): nside = 1 << order npix = hp.nside2npix(nside) stride = 1 << (2 * (top_order - order)) keep = (hp.pix2vec(nside, np.arange(npix), nest=True) * np.expand_dims(xyz0, 1)).sum(0) >= np.cos(np.deg2rad(30)) if order < top_order: mm = m.reshape((-1, stride)) keep &= (mm[:, :-1] == mm[:, 1:]).all(axis=1) m += hp.ud_grade(np.where(keep, np.nan, 0), nside_out=top_nside, order_in='NEST', order_out='NEST') else: keep &= ~np.isnan(m) for ipix in np.flatnonzero(keep): boundaries = hp.boundaries(nside, ipix, nest=True, step=1).T theta, phi = hp.vec2ang(boundaries) ra = np.rad2deg(phi) dec = np.rad2deg(0.5 * np.pi - theta) vertices = np.column_stack((ra, dec)) yield vertices
def enclosed_pixel_indices(self, nside_out): # Sanity if nside_out < self.nside: raise ( "Can't get enclosed pixel indices for lower resolution pixels!" ) if len(self.__epi) == 0: # Start with the central pixel, in case the size of the FOV is <= the pixel size self.__epi = np.asarray([ hp.ang2pix(self.nside, 0.5 * np.pi - self.__coord.dec.radian, self.__coord.ra.radian) ]) pixel_xyz_vertices = hp.boundaries(self.nside, pix=self.index) internal_pix = hp.query_polygon(nside_out, pixel_xyz_vertices, inclusive=False) if len(internal_pix) > 0: self.__epi = internal_pix return self.__epi
def get_hpmask_subpix_indices(submask_nside, submask_hpix, submask_border, nside_mask, hpix): """ """ nside_cutref = np.clip(submask_nside * 4, 256, nside_mask) # Find out which cutref pixels are inside the main pixel theta, phi = hp.pix2ang(nside_cutref, np.arange(hp.nside2npix(nside_cutref))) ipring_coarse = hp.ang2pix(submask_nside, theta, phi) inhpix, = np.where(ipring_coarse == submask_hpix) # If there is a border, we need to find the boundary pixels if submask_border > 0.0: boundaries = hp.boundaries(submask_nside, submask_hpix, step=nside_cutref/submask_nside) # These are all the pixels that touch the boundary for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(nside_cutref, boundaries[:, i], np.radians(submask_border), inclusive=True, fact=8) inhpix = np.append(inhpix, pixint) # Need to uniqify here because of overlapping pixels inhpix = np.unique(inhpix) # And now choose just those depthmap pixels that are in the inhpix region theta, phi = hp.pix2ang(nside_mask, hpix) ipring = hp.ang2pix(nside_cutref, theta, phi) _, use = esutil.numpy_util.match(inhpix, ipring) return use
def get_vert(pixel, nside, nest): """Get the coordinates for the vertices for a single Healpix index for a given resolution (nside) and schema (nest) Args: * All arguments are required pixel(int): Healpix index nside(int) : Healpix resolution given by nside parameters for the input pixel nest(bool): Pixelization schema, True: Nested Schema, False: Ring Schema Returns: Two lists with the RA and DEC positions for the vertices for the given pixel. """ # Get vertices in radian coordinates for a given pixel vertices = np.array( hp.vec2ang(np.transpose(hp.boundaries(nside, pixel, nest=nest)))) # To degrees vertices = vertices * 180. / np.pi diff = vertices[1] - vertices[1][0] # RA = 0 diff[diff > 180] -= 360 diff[diff < -180] += 360 ra_vert = vertices[1][0] + diff ra_vert = np.append(ra_vert, ra_vert[0]) dec_vert = 90.0 - vertices[0] dec_vert = np.append(dec_vert, dec_vert[0]) return ra_vert, dec_vert
def check_problematic_pixel(nside, ipix, a0, zmax, deviation=0.5, coord_system='gal'): """ Checks input pixel for exposure deviation within the corner points from more than certain threshold (default: 0.5). :param nside: nside of the healpy pixelization :param ipix: pixel number(s) :param a0: latitude of detector (-90, 90) in degrees (default: Auger) :param zmax: maximum acceptance zenith angle (0, 90) degrees :param deviation: maximum deviation between exposure values in pixel corners :param coord_system: choose between different coordinate systems - gal, eq, sgal, ecl """ npix = hp.nside2npix(nside) v = np.swapaxes(hp.boundaries(nside, np.arange(npix), step=1), 0, 1).reshape(3, -1) if coord_system != 'eq': v = getattr(coord, '%s2eq' % coord_system)(v) # exposure values of corner points exposure = coord.exposure_equatorial(coord.vec2ang(v)[1], a0, zmax).reshape((npix, 4)) # check for maximal deviation of corner points _min, _max = np.min(exposure, axis=-1), np.max(exposure, axis=-1) mask = _max > 0 eps = np.min(_min[_min > 0]) / 2. _min[_min < eps] = eps mask = mask * (_max / _min > (1 + deviation)) return mask[ipix]
def test_boundaries(self): nside = 2 corners = boundaries(nside, 5) corners_precomp = np.array( [[ 2.44708573e-17, 5.27046277e-01, 3.60797400e-01, 4.56383842e-17], [ 3.99652627e-01, 5.27046277e-01, 8.71041977e-01, 7.45355992e-01], [ 9.16666667e-01, 6.66666667e-01, 3.33333333e-01, 6.66666667e-01]]) np.testing.assert_array_almost_equal(corners, corners_precomp, decimal=8)
def plot_tessellation(self, facecmap: Optional[str] = 'Blues_r', ncols: int = 20, edgecolor: str = '#32519D', cell_centers: bool = True, markercolor: str = 'k', markersize: float = 2, linewidths=1, alpha: float = 0.9, seed: int = 0): vertices = [[hp.boundaries(self.nside, i).transpose()] for i in range(self.resolution)] self._plot_spherical_polygons(vertices, facecmap=facecmap, ncols=ncols, edgecolor=edgecolor, cell_centers=cell_centers, markercolor=markercolor, markersize=markersize, linewidths=linewidths, alpha=alpha, seed=seed)
def __init__(self, nSide, ident, nest, tractBuilder, ctrCoord, tractOverlap, wcs): """Set vertices from nside, ident, nest""" theta, phi = healpy.vec2ang( numpy.transpose(healpy.boundaries(nSide, ident, nest=nest))) vertexList = [angToCoord(thetaphi) for thetaphi in zip(theta, phi)] super(HealpixTractInfo, self).__init__(ident, tractBuilder, ctrCoord, vertexList, tractOverlap, wcs)
def make_polycoll(hpx_beam,plot_lim=[-90,-50],nsides=8,cmap=cm.gnuplot): #pixnums = np.arange(len(hpx_beam)) #theta,phi = hp.pix2ang(nsides,pixnums) #pix = pixnums[np.argwhere(theta<np.pi/2)].squeeze() pix = np.where(np.isnan(hpx_beam)==False)[0] boundaries = hp.boundaries(nsides,pix) verts = np.swapaxes(boundaries[:,0:2,:],1,2) coll = PolyCollection(verts, array=hpx_beam[np.isnan(hpx_beam)==False],\ cmap=cmap,edgecolors='none') return coll
def corners_ring(testcase): cs = [] for norder in range(16): nside = 1 << norder for i in range(1000): ipix = random.randrange(12 * nside * nside) args = (nside, ipix) cs.append( dict(args=args, expected=healpy.boundaries(*args).T.tolist())) testcase['corners_ring'] = cs
def getFgcmReferenceStarsHealpix(self, nside, pixel, filterList, nest=False): """ Get a reference catalog that overlaps a healpix pixel, using multiple filters. In addition, apply colorterms if available. Return format is a numpy recarray for use with fgcm, with the format: dtype = ([('ra', `np.float64`), ('dec', `np.float64`), ('refMag', `np.float32`, len(filterList)), ('refMagErr', `np.float32`, len(filterList)]) Reference magnitudes (AB) will be 99 for non-detections. Parameters ---------- nside: `int` Healpix nside of pixel to load pixel: `int` Healpix pixel of pixel to load filterList: `list` list of `str` of camera filter names. nest: `bool`, optional Is the pixel in nest format? Default is False. Returns ------- fgcmRefCat: `np.recarray` """ # Determine the size of the sky circle to load theta, phi = hp.pix2ang(nside, pixel, nest=nest) center = lsst.geom.SpherePoint(phi * lsst.geom.radians, (np.pi/2. - theta) * lsst.geom.radians) corners = hp.boundaries(nside, pixel, step=1, nest=nest) theta_phi = hp.vec2ang(np.transpose(corners)) radius = 0.0 * lsst.geom.radians for ctheta, cphi in zip(*theta_phi): rad = center.separation(lsst.geom.SpherePoint(cphi * lsst.geom.radians, (np.pi/2. - ctheta) * lsst.geom.radians)) if (rad > radius): radius = rad # Load the fgcm-format reference catalog fgcmRefCat = self.getFgcmReferenceStarsSkyCircle(center.getRa().asDegrees(), center.getDec().asDegrees(), radius.asDegrees(), filterList) catPix = hp.ang2pix(nside, np.radians(90.0 - fgcmRefCat['dec']), np.radians(fgcmRefCat['ra']), nest=nest) inPix, = np.where(catPix == pixel) return fgcmRefCat[inPix]
def natural_order(nside, ind, subn): assert nside <= subn if subn == nside: return np.array([ind]) sub = hp.query_polygon(2 * nside, hp.boundaries(nside, ind, nest=True).T, nest=True) assert len(sub) == 4 r = [natural_order(nside * 2, s, subn) for s in np.sort(sub)] return np.vstack((np.hstack((r[0], r[1])), np.hstack((r[2], r[3]))))
def __init__(self, NSIDE, lmax=10, clv=True): """ Args: NSIDE (int) : the healpix NSIDE parameter, must be a power of 2, less than 2**30 npix (int) : number of pixel in the X and Y axis of the final projected map rot_velocity (float) : rotation velocity of the star in the equator in km/s Returns: None """ self.NSIDE = int(NSIDE) self.hp_npix = hp.nside2npix(NSIDE) self.lmax = lmax self.n_coef_max = (1+lmax)**2 self.epsilon = 1e-3 self.l = np.arange(self.lmax+1) self.alpha = np.zeros(self.n_coef_max) self.beta = np.zeros(self.n_coef_max) self.gamma = np.zeros(self.n_coef_max) # self.rot_velocity = rot_velocity self.clv = clv # Generate the indices of all healpix pixels self.indices = np.arange(hp.nside2npix(NSIDE), dtype='int') self.n_healpix_pxl = len(self.indices) self.polar_angle, self.azimuthal_angle = hp.pixelfunc.pix2ang(self.NSIDE, np.arange(self.n_healpix_pxl)) self.pixel_vectors = np.array(hp.pixelfunc.pix2vec(self.NSIDE, self.indices)) # Compute LOS rotation velocity as v=w x r self.rotation_velocity = np.cross(np.array([0.0,0.0,1.0])[:,None], self.pixel_vectors, axisa=0, axisb=0, axisc=0) self.vec_boundaries = np.zeros((3,4,self.n_healpix_pxl)) for i in range(self.n_healpix_pxl): self.vec_boundaries[:,:,i] = hp.boundaries(self.NSIDE, i) self.Plm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.dPlm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.Clm = np.zeros((self.lmax+2, self.lmax+2)) for i in range(self.n_healpix_pxl): self.Plm[:,:,i], self.dPlm[:,:,i] = sp.lpmn(self.lmax+1, self.lmax+1, np.cos(self.polar_angle[i])) self.dPlm[:,:,i] *= -np.sin(self.polar_angle[i]) for l in range(self.lmax+2): for m in range(0, l+1): self.Clm[m,l] = np.sqrt((2.0*l+1) / (4.0*np.pi) * mi.factorial(l-m) / mi.factorial(l+m)) self.lambda0 = 5000.0 self.lande = 1.2 self.constant = -4.6686e-13 * self.lambda0 * self.lande * 3e5
def get_healsparse_subpix_indices(subpix_nside, subpix_hpix, subpix_border, coverage_nside): """ Retrieve the coverage pixels that intersect the region, with a border. Parameters ---------- subpix_nside: `int` Nside for the subregion subpix_hpix: `int` Pixel number for the subregion (ring format) subpix_border: `float` Border radius to cover outside subpix_hpix coverage_nside: `int` Nside of the healsparse coverage map """ # First, we need to know which pixel(s) from nside_coverage are covered by # subpix_hpix if subpix_nside == coverage_nside: # simply convert to nest covpix = hp.ring2nest(subpix_nside, subpix_hpix) elif subpix_nside > coverage_nside: # what pixel is this contained in? theta, phi = hp.pix2ang(subpix_nside, subpix_hpix, nest=False) covpix = hp.ang2pix(coverage_nside, theta, phi, nest=True) else: # This is subpix_nside < coverage_nside # what coverage pixels are contained in subpix_hpix? subpix_hpix_nest = hp.ring2nest(subpix_nside, subpix_hpix) bit_shift = 2 * int(np.round(np.log(coverage_nside / subpix_nside) / np.log(2))) n_pix = 2**bit_shift covpix = np.left_shift(subpix_hpix_nest, bit_shift) + np.arange(n_pix) # And now if we have a border... if subpix_border > 0.0: nside_testing = max([coverage_nside * 4, subpix_nside * 4]) boundaries = hp.boundaries(subpix_nside, subpix_hpix, step=nside_testing/subpix_nside) extrapix = np.zeros(0, dtype=np.int64) # These are pixels that touch the boundary for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(nside_testing, boundaries[:, i], np.radians(subpix_border), inclusive=True, fact=8) extrapix = np.append(extrapix, pixint) extrapix = np.unique(extrapix) theta, phi = hp.pix2ang(nside_testing, extrapix) covpix = np.unique(np.append(covpix, hp.ang2pix(coverage_nside, theta, phi, nest=True))) return covpix
def healpix_boundaries(ipix, nside=256, step=2, nest=True, convention='spherical', units='degrees'): """ return an array of points on the boundaries of the healpixels with ids given by ipix in the form of (colongitudes, colatitudes) Parameters ---------- ipix : `np.ndarray`, dtype int healpixel ids of pixels whose boundaries are required nside : int, defaults to 256 Healpix NSIDE step : int factor by which the number of points in the corners (4) are stepped up. ie. a step of 2 returns 8 points along the boundaries of the Healpixel inlcuding the corners nest : Bool, defaults to True using the `nested` rather than `ring` scheme. convention : {'spherical', 'celestial'}, defaults to 'spherical' (theta, phi) of the usual spherical coordinate system or (ra, dec) units : {'degrees', 'radians'} , defaults to 'degrees' units in which the points are returned Returns -------- tuple (colongitude, colatitude) .. note: This also produces the 'inner' boundaries for connected pixels. """ corner_vecs = hp.boundaries(nside, ipix, step=step, nest=nest) if len(np.shape(corner_vecs)) > 2: corner_vecs = np.concatenate(corner_vecs, axis=1) phi_theta = hp.vec2ang(np.transpose(corner_vecs)) # These are in radians and spherical coordinates by construction theta, phi = phi_theta if convention == 'celestial': return convertToCelestialCoordinates(theta, phi, output_unit=units) # else return in spherical coordinates, but convert to degrees if requested if units == 'degrees': lon = np.degrees(phi) lat = np.degrees(theta) else: lon = phi lat = theta return lon, lat
def prepare_sampling(nside): os.makedirs("cache", exist_ok=True) filename = f'cache/sampling-{nside}.npy' if os.path.exists(filename): sample_info = np.load(filename) return sample_info npix = hp.nside2npix(nside) p = np.arange(npix, dtype=int) vertices = hp.boundaries(nside, p) sample_info = [] for v in vertices: sample_info.append(prepare_quadrilateral_sampling(v)) np.save(filename, sample_info) return sample_info
def polygon(self): if not self.__polygon: pixel_xyz_vertices = hp.boundaries(self.nside, pix=self.index) theta, phi = hp.vec2ang(np.transpose(pixel_xyz_vertices)) ra_rad = phi dec_rad = (np.pi / 2. - theta) pixel_radian_vertices = [[ra, dec] for ra, dec in zip(ra_rad, dec_rad)] self.__polygon = geometry.Polygon(pixel_radian_vertices) return [self.__polygon]
def getCountAtLocations(ra, dec, nside=512, return_vertices=False): """Get number density of objects from RA/Dec in HealPix cells. Requires: healpy Args: ra: list of rectascensions dec: list of declinations nside: HealPix nside return_vertices: whether to also return the boundaries of HealPix cells Returns: bc, ra_, dec_, [vertices] bc: count of objects [per arcmin^2] in a HealPix cell if count > 0 ra_: rectascension of the cell center (same format as ra/dec) dec_: declinations of the cell center (same format as ra/dec) vertices: (N,4,2), RA/Dec coordinates of 4 boundary points of cell """ import healpy as hp # get healpix pixels ipix = hp.ang2pix(nside, (90 - dec) / 180 * np.pi, ra / 180 * np.pi, nest=False) # count how often each pixel is hit bc = np.bincount(ipix) pixels = np.nonzero(bc)[0] bc = bc[bc > 0] / hp.nside2resol(nside, arcmin=True)**2 # in arcmin^-2 # get position of each pixel in RA/Dec theta, phi = hp.pix2ang(nside, pixels, nest=False) ra_ = phi * 180 / np.pi dec_ = 90 - theta * 180 / np.pi # get the vertices that confine each pixel # convert to RA/Dec (thanks to Eric Huff) if return_vertices: vertices = np.zeros((pixels.size, 4, 2)) for i in xrange(pixels.size): corners = hp.vec2ang(np.transpose(hp.boundaries(nside, pixels[i]))) corners = np.array(corners) * 180. / np.pi diff = corners[1] - corners[1][0] diff[diff > 180] -= 360 diff[diff < -180] += 360 corners[1] = corners[1][0] + diff vertices[i, :, 0] = corners[1] vertices[i, :, 1] = 90.0 - corners[0] return bc, ra_, dec_, vertices else: return bc, ra_, dec_
def generate_uniform_random_ra_dec_healpixel(n, pix, nside, nest=False): """ Parameters ---------- n : int number of random points needed pix : int healpixel ID nside : int number of healpixel nside, must be 2**k nest : bool, optional using healpixel nest or ring ordering Returns ------- ra : ndarray 1d array of length n that contains RA in degrees dec : ndarray 1d array of length n that contains Dec in degrees """ ra, dec = hp.vec2ang(hp.boundaries(nside, pix, 1, nest=nest).T, lonlat=True) ra_dec_min_max = ra.min(), ra.max(), dec.min(), dec.max() ra = np.empty(n) dec = np.empty_like(ra) n_needed = n while n_needed > 0: ra_this, dec_this = generate_uniform_random_ra_dec_min_max( n_needed * 2, *ra_dec_min_max) mask = np.where( hp.ang2pix(nside, ra_this, dec_this, nest=nest, lonlat=True) == pix)[0] count_this = mask.size if n_needed - count_this < 0: count_this = n_needed mask = mask[:n_needed] s = slice( -n_needed, -n_needed + count_this if -n_needed + count_this < 0 else None) ra[s] = ra_this[mask] dec[s] = dec_this[mask] n_needed -= count_this return ra, dec
def pixel_boundaries(props, pixel): scheme = choose_pixelization(**dict(props)) # area in arcmin^2 area = scheme.pixel_area(degrees=True) * 60 * 60 boundaries = scheme.pixel_boundaries() if props['pixelization'] == 'healpix': boundaries = healpy.boundaries(props['nside'], pixel) area = healpy.nside2pixarea(nside, degrees=True) * 60. * 60. elif props['pixelization'] == 'gnomonic': boundaries = pixel_boundaries(maps_file['maps/depth'].attrs) pix_size_deg = maps_file['maps/depth'].attrs['pixel_size'] area = (pix_size_deg * 60. * 60.)**2 else: raise ValueError(f"Unknown pixelization scheme: {pixelization}")
def getCountAtLocations(ra, dec, nside=512, return_vertices=False): """Get number density of objects from RA/Dec in HealPix cells. Requires: healpy Args: ra: list of rectascensions dec: list of declinations nside: HealPix nside return_vertices: whether to also return the boundaries of HealPix cells Returns: bc, ra_, dec_, [vertices] bc: count of objects [per arcmin^2] in a HealPix cell if count > 0 ra_: rectascension of the cell center (same format as ra/dec) dec_: declinations of the cell center (same format as ra/dec) vertices: (N,4,2), RA/Dec coordinates of 4 boundary points of cell """ import healpy as hp # get healpix pixels ipix = hp.ang2pix(nside, (90-dec)/180*np.pi, ra/180*np.pi, nest=False) # count how often each pixel is hit bc = np.bincount(ipix) pixels = np.nonzero(bc)[0] bc = bc[bc>0] / hp.nside2resol(nside, arcmin=True)**2 # in arcmin^-2 # get position of each pixel in RA/Dec theta, phi = hp.pix2ang(nside, pixels, nest=False) ra_ = phi*180/np.pi dec_ = 90 - theta*180/np.pi # get the vertices that confine each pixel # convert to RA/Dec (thanks to Eric Huff) if return_vertices: vertices = np.zeros((pixels.size, 4, 2)) for i in xrange(pixels.size): corners = hp.vec2ang(np.transpose(hp.boundaries(nside,pixels[i]))) corners = np.array(corners) * 180. / np.pi diff = corners[1] - corners[1][0] diff[diff > 180] -= 360 diff[diff < -180] += 360 corners[1] = corners[1][0] + diff vertices[i,:,0] = corners[1] vertices[i,:,1] = 90.0 - corners[0] return bc, ra_, dec_, vertices else: return bc, ra_, dec_
def boundary(self, k, steps=None, max_stepsize=None, edge=1e-6): """ Return boundary of a bin; used for drawing polygons. If steps is None, max_stepsize is used to automatically determine the appropriate step size. """ if max_stepsize is None: max_stepsize = self.max_stepsize if steps is None: steps = self._determine_steps(max_stepsize=max_stepsize) bd = hp.boundaries(self.nside, k, step=steps, nest=self.nest) dec_raw, ra_raw = hp.vec2ang(np.transpose(bd)) ra = (ra_raw / _d2r) % 360 dec = 90 - dec_raw / _d2r return self.split_bin(ra, dec, max_stepsize, edge)
def get_subpixel_indices(galtable, hpix=None, border=0.0, nside=0): """ Routine to get subpixel indices from a galaxy table. Parameters ---------- galtable: `redmapper.Catalog` A redmapper galaxy table master catalog hpix: `int`, optional Healpix number (ring format) of sub-region. Default is 0 (full catalog). border: `float`, optional Border around hpix (in degrees) to find pixels. Default is 0.0. nside: `int`, optional Nside of healpix subregion. Default is 0 (full catalog). Returns ------- indices: `np.array` Integer array of indices of galaxy table pixels in the subregion. """ if hpix is None or nside == 0: return np.arange(galtable.filenames.size) theta, phi = hp.pix2ang(galtable.nside, galtable.hpix) ipring_big = hp.ang2pix(nside, theta, phi) indices, = np.where(ipring_big == hpix) if border > 0.0: # now we need to find the extra boundary... boundaries = hp.boundaries(nside, hpix, step=galtable.nside / nside) inhpix = galtable.hpix[indices] for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(galtable.nside, boundaries[:, i], border * np.pi / 180., inclusive=True, fact=8) inhpix = np.append(inhpix, pixint) inhpix = np.unique(inhpix) _, indices = esutil.numpy_util.match(inhpix, galtable.hpix) return indices
def gen_catalog_bin(ngal): """ Generate a random catalog for a single bin using healpy routines :param ngal: The number of galaxies per pixel :type ngal: :class:`lsssys.Map` :return: The right ascension and declination of the generated catalog :rtype: ``tuple`` of 2 :class:`numpy.ndarray` of ``float`` """ pix = np.where(ngal.data > 0.)[0] n_gal = ngal.data[pix].astype(int) highres_nside = ngal.nside * next_power_of_2(2 * n_gal.max()) pix_nest = hp.ring2nest(ngal.nside, pix) corners = np.array( [c.T for c in hp.boundaries(ngal.nside, pix_nest, nest=True)]) high_res_pix = np.concatenate([ np.random.choice(hp.query_polygon(highres_nside, corn, nest=True), n) for corn, n in zip(corners, n_gal) ]) hpix_highres = hu.HealPix("nest", highres_nside) return hpix_highres.pix2eq(high_res_pix)
def write_reg(self,filename): """ Write a ds9 region file that represents this region as a set of diamonds. :param filename: file to write :return: None """ with open(filename,'w') as out: for d in xrange(1,self.maxdepth+1): for p in self.pixeldict[d]: line="fk5; polygon(" #the following int() gets around some problems with np.int64 that exist prior to numpy v 1.8.1 vectors = zip(*hp.boundaries(2**d,int(p),step=1,nest=True)) positions=[] for sky in self.vec2sky(np.array(vectors),degrees=True): ra, dec = sky pos= SkyCoord(ra/15,dec,unit=(u.degree,u.degree)) positions.append( pos.ra.to_string(sep=':',precision=2)) positions.append( pos.dec.to_string(sep=':',precision=2)) line += ','.join(positions) line += ")" print>>out, line return
def get_subpixel_indices(galtable, hpix=None, border=0.0, nside=0): """ Routine to get subpixel indices from a galaxy table. Parameters ---------- galtable: `redmapper.Catalog` A redmapper galaxy table master catalog hpix: `int`, optional Healpix number (ring format) of sub-region. Default is 0 (full catalog). border: `float`, optional Border around hpix (in degrees) to find pixels. Default is 0.0. nside: `int`, optional Nside of healpix subregion. Default is 0 (full catalog). Returns ------- indices: `np.array` Integer array of indices of galaxy table pixels in the subregion. """ if hpix is None or nside == 0: return np.arange(galtable.filenames.size) theta, phi = hp.pix2ang(galtable.nside, galtable.hpix) ipring_big = hp.ang2pix(nside, theta, phi) indices, = np.where(ipring_big == hpix) if border > 0.0: # now we need to find the extra boundary... boundaries = hp.boundaries(nside, hpix, step=galtable.nside/nside) inhpix = galtable.hpix[indices] for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(galtable.nside, boundaries[:, i], border*np.pi/180., inclusive=True, fact=8) inhpix = np.append(inhpix, pixint) inhpix = np.unique(inhpix) _, indices = esutil.numpy_util.match(inhpix, galtable.hpix) return indices
def getHealpixVertices(pixels, nside, nest=False): """Get polygon vertices for list of HealPix pixels. Args: pixels: list of HealPix pixels nside: HealPix nside nest: HealPix nesting scheme Returns: vertices: (N,4,2), RA/Dec coordinates of 4 boundary points of cell """ corners = np.transpose(hp.boundaries(nside, pixels, step=1, nest=nest), (0, 2, 1)) corners_x = corners[:, :, 0].flatten() corners_y = corners[:, :, 1].flatten() corners_z = corners[:, :, 2].flatten() vertices_lon, vertices_lat = hp.rotator.vec2dir(corners_x, corners_y, corners_z, lonlat=True) return np.stack([vertices_lon.reshape(-1, 4), vertices_lat.reshape(-1, 4)], axis=-1)
def run(self, dataSlice, slicePoint=None): # RA and Dec from dataSlice doesn't necessarily match healpix RA = dataSlice['fieldRA'][0] Dec = dataSlice['fieldDec'][0] # Get RA and Dec from slicer RA = slicePoint['ra'] Dec = slicePoint['dec'] nside = slicePoint['nside'] # get the boundaries from HealPix bounding = hp.boundaries(nside, slicePoint['sid'], step=1).T inside_val = np.asarray( sgv.radec_to_vector(slicePoint['ra'], slicePoint['dec'], degrees=False)) test_pointing = SphericalPolygon(bounding, inside_val) overlap_area = [ test_pointing.intersection(survey_polygon).area() for survey_polygon in survey_list[self.region_name] ] total = sum(overlap_area) healpix_area = test_pointing.area() return min(total, 4 * np.pi - total)
def getHealpixVertices(pixels, nside, nest=False): """Get polygon vertices for list of HealPix pixels. Args: pixels: list of HealPix pixels nside: HealPix nside nest: HealPix nesting scheme Returns: vertices: (N,4,2), RA/Dec coordinates of 4 boundary points of cell """ vertices = np.zeros((pixels.size, 4, 2)) for i in xrange(pixels.size): corners = hp.vec2ang( np.transpose(hp.boundaries(nside, pixels[i], nest=nest))) corners = np.array(corners) * 180. / np.pi diff = corners[1] - corners[1][0] diff[diff > 180] -= 360 diff[diff < -180] += 360 corners[1] = corners[1][0] + diff vertices[i, :, 0] = corners[1] vertices[i, :, 1] = 90.0 - corners[0] return vertices
def jsa_tile_wcs(header): """ Determine WCS information for a JSA tile. """ # Find tile number and Nside. tile_number = header['TILENUM'] match = tilenum_comment.search(header.comments['TILENUM']) if not match: raise CAOMError('Cannot find Nside in TILENUM comment') nside = int(match.group(1)) # Get corner coordinates. (colatitude, longitude) = healpy.vec2ang(np.transpose( healpy.boundaries(nside, tile_number, nest=True))) assert len(colatitude) == 4 assert len(longitude) == 4 # Convert to a CAOM-2 polygon. Note the ordering appears to be # the other way round from what CAOM-2 requires, hence iteration # over the corners backwards. tile = CoordPolygon2D() for i in range(3, -1, -1): tile.vertices.append(ValueCoord2D( 180 * longitude[i] / math.pi, 90 - (180 * colatitude[i] / math.pi))) spatial_axes = CoordAxis2D(Axis('RA', 'deg'), Axis('DEC', 'deg')) spatial_axes.bounds = tile return SpatialWCS(spatial_axes, coordsys='ICRS', equinox=2000.0)
def getHealpixVertices(pixels, nside, nest=False): """Get polygon vertices for list of HealPix pixels. Requires: healpy Args: pixels: list of HealPix pixels nside: HealPix nside nest: HealPix nesting scheme Returns: vertices: (N,4,2), RA/Dec coordinates of 4 boundary points of cell """ vertices = np.zeros((pixels.size, 4, 2)) for i in xrange(pixels.size): corners = hp.vec2ang(np.transpose(hp.boundaries(nside,pixels[i], nest=nest))) corners = np.array(corners) * 180. / np.pi diff = corners[1] - corners[1][0] diff[diff > 180] -= 360 diff[diff < -180] += 360 corners[1] = corners[1][0] + diff vertices[i,:,0] = corners[1] vertices[i,:,1] = 90.0 - corners[0] return vertices
def from_galfile(cls, filename, nside=0, hpix=0, border=0.0): """ Name: from_galfile Purpose: do the actual reading in of the data fields in some galaxy catalog file Calling Squence: TODO Inputs: filename: a name of a galaxy catalog file Optional Inputs: nside: integer healpix nside of sub-pixel hpix: integer healpix pixel (ring order) of sub-pixel Outputs: A galaxy catalog object """ if hpix == 0: _hpix = None else: _hpix = hpix # do we have appropriate keywords if _hpix is not None and nside is None: raise ValueError("If hpix is specified, must also specify nside") if border < 0.0: raise ValueError("Border must be >= 0.0.") # ensure that nside is valid, and hpix is within range (if necessary) if nside > 0: if not hp.isnsideok(nside): raise ValueError("Nside not valid") if _hpix is not None: if _hpix < 0 or _hpix >= hp.nside2npix(nside): raise ValueError("hpix out of range.") # check that the file is there and the right format # this will raise an exception if it's not there. hdr = fitsio.read_header(filename, ext=1) pixelated, fitsformat = hdr.get("PIXELS", 0), hdr.get("FITS", 0) if not pixelated: cat = fitsio.read(filename, ext=1, upper=True) return cls(cat) # this is to keep us from trying to use old IDL galfiles if not fitsformat: raise ValueError("Input galfile must describe fits files.") # now we can read in the galaxy table summary file... tab = fitsio.read(filename, ext=1, upper=True) nside_tab = tab[0]['NSIDE'] if nside > nside_tab: raise ValueError("""Requested nside (%d) must not be larger than table nside (%d).""" % (nside, nside_tab)) # which files do we want to read? path = os.path.dirname(os.path.abspath(filename)) if _hpix is None: # all of them! indices = np.arange(tab[0]['FILENAMES'].size) else: # first we need all the pixels that are contained in the big pixel theta, phi = hp.pix2ang(nside_tab, tab[0]['HPIX']) ipring_big = hp.ang2pix(nside, theta, phi) indices, = np.where(ipring_big == _hpix) if border > 0.0: # now we need to find the extra boundary... boundaries = hp.boundaries(nside, _hpix, step=nside_tab/nside) inhpix = tab[0]['HPIX'][indices] for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(nside_tab, boundaries[:,i], border*np.pi/180., inclusive=True, fact=8) inhpix = np.append(inhpix, pixint) inhpix = np.unique(inhpix) _, indices = esutil.numpy_util.match(inhpix, tab[0]['HPIX']) # create the catalog array to read into elt = fitsio.read('%s/%s' % (path, tab[0]['FILENAMES'][indices[0]].decode()),ext=1, rows=0, upper=True) cat = np.zeros(np.sum(tab[0]['NGALS'][indices]), dtype=elt.dtype) # read the files ctr = 0 for index in indices: cat[ctr : ctr+tab[0]['NGALS'][index]] = fitsio.read('%s/%s' % (path, tab[0]['FILENAMES'][index].decode()), ext=1, upper=True) ctr += tab[0]['NGALS'][index] # In the IDL version this is trimmed to the precise boundary requested. # that's easy in simplepix. Not sure how to do in healpix. return cls(cat)
def tiles2fracpix(nside, step=1, tiles=None, radius=None, fact=4): ''' Returns a sorted array of just the *fractional* pixels that overlap the tiles Optional Args: nside: integer healpix nside, 2**k where 0 < k < 30 step: The number of integration steps around the edges of a HEALPix pixel. step=1 means just the pixel vertices (e.g., see http://healpy.readthedocs.io/en/latest/generated/healpy.boundaries.html) step=2 means the vertices and the corners and the points halfway between the vertices. tiles: Table-like with RA,DEC columns; or None to use all DESI tiles from desimodel.io.load_tiles() radius: tile radius in degrees; if None use desimodel.focalplane.get_tile_radius_deg() fact: factor healpy uses to resolve pixel overlaps. When this is large there are fewer false positives at the expense of run time (although fact=2**8 seems fast). Must be a power of 2 Returns fracpix: integer array of pixel numbers that cover these tiles, *excluding pixels that fully overlap the tiles* (i.e., just pixels that *partially* overlap the tiles). The integers are sorted. Notes: there are potentially malicious cases where a pixel just brushes a tile, such that there is a very small area where the pixel overlaps the tile. To guard against these case, call this function with progressively larger step values until it converges. ''' #ADM set up healpy and set default tiles and radius import healpy as hp import desimodel if tiles is None: tiles = desimodel.io.load_tiles() if radius is None: radius = desimodel.focalplane.get_tile_radius_deg() #ADM obtain ALL pixels that overlap the tiles (and perhaps a #ADM few more if fact is a small number pix = desimodel.footprint.tiles2pix(nside, tiles=tiles, radius=radius, fact=fact) #ADM the recovered number of pixels, and the total number of points #ADM that will be integrated around the boundary of the pixel npix = len(pix) nvertsperpix = 4 * step #ADM find points around the boundary of all pixels in Cartesian coordinates xyzverts = hp.boundaries(nside, pix, step=step, nest=True) #ADM convert to RA/Dec theta, phi = hp.vec2ang(np.hstack(xyzverts).T) ra, dec = np.degrees(phi), 90 - np.degrees(theta) #ADM calculate which boundary points are in the tiles verts_in = desimodel.footprint.is_point_in_desi(tiles, ra, dec, radius=radius) #ADM reshape this into an array with nvertsperpix columns pix_verts_in = np.reshape(verts_in, (npix, nvertsperpix)) #ADM any row with a column not in the tiles must be a fractional pixel isfracpix = ~np.all(pix_verts_in, axis=1) #ADM the pixel integers where pixels are fractional return pix[np.where(isfracpix)]
def plot_healpix_map(data, nest=False, cmap='viridis', colorbar=True, label=None, basemap=None, vlimits=None): """Plot a healpix map using an all-sky projection. Pass the data array through :func:`prepare_data` to select a subset to plot and clip the color map to specified values or percentiles. This function is similar to :func:`plot_grid_map` but is generally slower at high resolution and has less elegant handling of pixels that wrap around in RA, which are not drawn. Requires that matplotlib, basemap, and healpy are installed. Parameters ---------- data : array or masked array 1D array of data associated with each healpix. Must have a size that exactly matches the number of pixels for some NSIDE value. Use the output of :func:`prepare_data` as a convenient way to specify data cuts and color map clipping. nest : bool If True, assume NESTED pixel ordering. Otheriwse, assume RING pixel ordering. cmap : colormap name or object Matplotlib colormap to use for mapping data values to colors. colorbar : bool Draw a colorbar below the map when True. label : str or None Label to display under the colorbar. Ignored unless colorbar is True. basemap : Basemap object or None Use the specified basemap or create a default basemap using :func:`init_sky` when None. Returns ------- basemap The basemap used for the plot, which will match the input basemap provided, or be a newly created basemap if None was provided. """ import healpy as hp import matplotlib.pyplot as plt import matplotlib.colors from matplotlib.collections import PolyCollection data = prepare_data(data) if len(data.shape) != 1: raise ValueError('Invalid data array, should be 1D.') nside = hp.npix2nside(len(data)) if basemap is None: basemap = init_sky() # Get pixel boundaries as quadrilaterals. corners = hp.boundaries(nside, np.arange(len(data)), step=1, nest=nest) corner_theta, corner_phi = hp.vec2ang(corners.transpose(0, 2, 1)) corner_ra, corner_dec = (np.degrees(corner_phi), np.degrees(np.pi / 2 - corner_theta)) # Convert sky coords to map coords. x, y = basemap(corner_ra, corner_dec) # Regroup into pixel corners. verts = np.array([x.reshape(-1, 4), y.reshape(-1, 4)]).transpose(1, 2, 0) # Find and mask any pixels that wrap around in RA. uv_verts = np.array( [corner_phi.reshape(-1, 4), corner_theta.reshape(-1, 4)]).transpose(1, 2, 0) theta_edge = np.unique(uv_verts[:, :, 1]) phi_edge = np.radians(basemap.lonmax) eps = 0.1 * np.sqrt(hp.nside2pixarea(nside)) wrapped1 = hp.ang2pix(nside, theta_edge, phi_edge - eps, nest=nest) wrapped2 = hp.ang2pix(nside, theta_edge, phi_edge + eps, nest=nest) wrapped = np.unique(np.hstack((wrapped1, wrapped2))) data.mask[wrapped] = True # Normalize the data using its vmin, vmax attributes, if present. try: if vlimits is None: norm = matplotlib.colors.Normalize(vmin=data.vmin, vmax=data.vmax) else: norm = matplotlib.colors.Normalize(vmin=vlimits[0], vmax=vlimits[1]) except AttributeError: norm = None # Make the collection and add it to the plot. collection = PolyCollection(verts, array=data, cmap=cmap, norm=norm, edgecolors='none') axes = plt.gca() if basemap.ax is None else basemap.ax axes.add_collection(collection) axes.autoscale_view() if colorbar: bar = plt.colorbar(collection, ax=basemap.ax, orientation='horizontal', spacing='proportional', pad=0.01, aspect=50) if label: bar.set_label(label) return basemap
def bboxcorners(ipix,nside): bounds = healpy.boundaries(nside,ipix,step=1,nest=True) vectranspose = bounds.T result = map(polar2radec, numpy.array(healpy.vec2ang(vectranspose))[0],numpy.array(healpy.vec2ang(vectranspose))[1]) return result
def _plot_poly(self, proj='AIT', step=1, ax=None): """Plot the map using a collection of polygons. Parameters ---------- proj : string, optional Any valid WCS projection type. step : int Set the number vertices that will be computed for each pixel in multiples of 4. """ # FIXME: At the moment this only works for all-sky maps if the # projection is centered at (0,0) # FIXME: Figure out how to force a square aspect-ratio like imshow import matplotlib.pyplot as plt from matplotlib.patches import Polygon from matplotlib.collections import PatchCollection import healpy as hp wcs = self.geom.make_wcs(proj=proj, oversample=1) if ax is None: fig = plt.gcf() ax = fig.add_subplot(111, projection=wcs.wcs, aspect='equal') wcs_lonlat = wcs.center_coord[:2] idx = self.geom.get_idx() vtx = hp.boundaries(self.geom.nside, idx[0], nest=self.geom.nest, step=step) theta, phi = hp.vec2ang(np.rollaxis(vtx, 2)) theta = theta.reshape((4 * step, -1)).T phi = phi.reshape((4 * step, -1)).T patches = [] data = [] def get_angle(x, t): return 180. - (180. - x + t) % 360. for i, (x, y) in enumerate(zip(phi, theta)): lon, lat = np.degrees(x), np.degrees(np.pi / 2. - y) # Add a small ofset to avoid vertices wrapping to the # other size of the projection if get_angle(np.median(lon), wcs_lonlat[0]) > 0.0: idx = wcs.coord_to_pix((lon - 1E-4, lat)) else: idx = wcs.coord_to_pix((lon + 1E-4, lat)) dist = np.max(np.abs(idx[0][0] - idx[0])) # Split pixels that wrap around the edges of the projection if (dist > wcs.npix[0] / 1.5): lon, lat = np.degrees(x), np.degrees(np.pi / 2. - y) lon0 = lon - 1E-4 lon1 = lon + 1E-4 pix0 = wcs.coord_to_pix((lon0, lat)) pix1 = wcs.coord_to_pix((lon1, lat)) idx0 = np.argsort(pix0[0]) idx1 = np.argsort(pix1[0]) pix0 = (pix0[0][idx0][:3], pix0[1][idx0][:3]) pix1 = (pix1[0][idx1][1:], pix1[1][idx1][1:]) patches.append(Polygon(np.vstack((pix0[0], pix0[1])).T, True)) patches.append(Polygon(np.vstack((pix1[0], pix1[1])).T, True)) data.append(self.data[i]) data.append(self.data[i]) else: polygon = Polygon(np.vstack((idx[0], idx[1])).T, True) patches.append(polygon) data.append(self.data[i]) p = PatchCollection(patches, linewidths=0, edgecolors='None') p.set_array(np.array(data)) ax.add_collection(p) ax.autoscale_view() ax.coords.grid(color='w', linestyle=':', linewidth=0.5) return fig, ax, p
band = row['filter'] frame_ang = np.array([np.radians(90 - visit_dec), np.radians(visit_ra) ]) #vertices of visit frame in theta_phi coords polyframe = Polygon(np.transpose(frame_ang)) #polygon of visit frame ipix_inframe = hp.query_polygon(nsideSparse, hp.ang2vec(*frame_ang), nest=True, inclusive=True) #pixel inside visit frame ipix_inter = set(ipix_infield).intersection( set(ipix_inframe)) #pixel inside visit frame and DC2 field if bool(ipix_inter): for ipix in ipix_inter: pixvec = hp.boundaries(nsideSparse, ipix, nest=True) #vertcies of healpix pixel polypix = Polygon(np.transpose(hp.vec2ang( np.transpose(pixvec)))) #polygon of healpix pixel if polyframe.contains(polypix): ind = np.where(ipix_infield == ipix)[0][0] nvisit[band][ind] += 1. for i, dataname in enumerate(datanames): mp[band][i][ind] += row[dataname] * 1. elif polyframe.intersects(polypix): ind = np.where(ipix_infield == ipix)[0][0] area = polyframe.intersection( polypix ).area / polypix.area #fraction of pixel inside visit frame nvisit[band][ind] += area for i, dataname in enumerate(datanames): mp[band][i][ind] += row[dataname] * area
def __init__(self, nSide, ident, nest, patchInnerDimensions, patchBorder, ctrCoord, tractOverlap, wcs): """Set vertices from nside, ident, nest""" theta, phi = healpy.vec2ang(numpy.transpose(healpy.boundaries(nSide, ident, nest=nest))) vertexList = [angToCoord(thetaphi) for thetaphi in zip(theta,phi)] super(HealpixTractInfo, self).__init__(ident, patchInnerDimensions, patchBorder, ctrCoord, vertexList, tractOverlap, wcs)
def contour(m, levels, nest=False, degrees=False, simplify=True): try: import networkx as nx except: raise RuntimeError('This function requires the networkx package.') # Determine HEALPix resolution npix = len(m) nside = hp.npix2nside(npix) min_area = 0.4 * hp.nside2pixarea(nside) # Compute faces, vertices, and neighbors. # vertices is an N X 3 array of the distinct vertices of the HEALPix faces. # faces is an npix X 4 array mapping HEALPix faces to their vertices. # neighbors is an npix X 4 array mapping faces to their nearest neighbors. faces = np.ascontiguousarray( np.rollaxis(hp.boundaries(nside, np.arange(npix), nest=nest), 2, 1)) dtype = faces.dtype faces = faces.view(np.dtype((np.void, dtype.itemsize * 3))) vertices, faces = np.unique(faces.ravel(), return_inverse=True) faces = faces.reshape(-1, 4) vertices = vertices.view(dtype).reshape(-1, 3) neighbors = hp.get_all_neighbours(nside, np.arange(npix), nest=nest)[::2].T # Loop over the requested contours. paths = [] for level in levels: # Find credible region indicator = (m >= level) # Construct a graph of the eges of the contour. graph = nx.Graph() face_pairs = set() for ipix1, ipix2 in enumerate(neighbors): for ipix2 in ipix2: # Determine if we have already considered this pair of faces. new_face_pair = frozenset((ipix1, ipix2)) if new_face_pair in face_pairs: continue face_pairs.add(new_face_pair) # Determine if this pair of faces are on a boundary of the # credible level. if indicator[ipix1] == indicator[ipix2]: continue # Add all common edges of this pair of faces. i1 = np.concatenate((faces[ipix1], [faces[ipix1][0]])) i2 = np.concatenate((faces[ipix2], [faces[ipix2][0]])) edges1 = frozenset(frozenset(_) for _ in zip(i1[:-1], i1[1:])) edges2 = frozenset(frozenset(_) for _ in zip(i2[:-1], i2[1:])) for edge in edges1 & edges2: graph.add_edge(*edge) graph = nx.freeze(graph) # Record a closed path for each cycle in the graph. cycles = [ np.take(vertices, cycle, axis=0) for cycle in nx.cycle_basis(graph) ] # Simplify paths if requested if simplify: cycles = [_simplify(cycle, min_area) for cycle in cycles] cycles = [cycle for cycle in cycles if len(cycle) > 2] # Convert to lists cycles = [ _vec2radec(cycle, degrees=degrees).tolist() for cycle in cycles ] # Add to output paths paths.append([cycle + [cycle[0]] for cycle in cycles]) return paths
def _plot_poly(self, proj="AIT", step=1, ax=None): """Plot the map using a collection of polygons. Parameters ---------- proj : string, optional Any valid WCS projection type. step : int Set the number vertices that will be computed for each pixel in multiples of 4. """ # FIXME: At the moment this only works for all-sky maps if the # projection is centered at (0,0) # FIXME: Figure out how to force a square aspect-ratio like imshow import matplotlib.pyplot as plt from matplotlib.patches import Polygon from matplotlib.collections import PatchCollection import healpy as hp wcs = self.geom.to_wcs_geom(proj=proj, oversample=1) if ax is None: fig = plt.gcf() ax = fig.add_subplot(111, projection=wcs.wcs, aspect="equal") wcs_lonlat = wcs.center_coord[:2] idx = self.geom.get_idx() vtx = hp.boundaries(self.geom.nside, idx[0], nest=self.geom.nest, step=step) theta, phi = hp.vec2ang(np.rollaxis(vtx, 2)) theta = theta.reshape((4 * step, -1)).T phi = phi.reshape((4 * step, -1)).T patches = [] data = [] def get_angle(x, t): return 180.0 - (180.0 - x + t) % 360.0 for i, (x, y) in enumerate(zip(phi, theta)): lon, lat = np.degrees(x), np.degrees(np.pi / 2.0 - y) # Add a small ofset to avoid vertices wrapping to the # other size of the projection if get_angle(np.median(lon), wcs_lonlat[0].to_value("deg")) > 0: idx = wcs.coord_to_pix((lon - 1e-4, lat)) else: idx = wcs.coord_to_pix((lon + 1e-4, lat)) dist = np.max(np.abs(idx[0][0] - idx[0])) # Split pixels that wrap around the edges of the projection if dist > wcs.npix[0] / 1.5: lon, lat = np.degrees(x), np.degrees(np.pi / 2.0 - y) lon0 = lon - 1e-4 lon1 = lon + 1e-4 pix0 = wcs.coord_to_pix((lon0, lat)) pix1 = wcs.coord_to_pix((lon1, lat)) idx0 = np.argsort(pix0[0]) idx1 = np.argsort(pix1[0]) pix0 = (pix0[0][idx0][:3], pix0[1][idx0][:3]) pix1 = (pix1[0][idx1][1:], pix1[1][idx1][1:]) patches.append(Polygon(np.vstack((pix0[0], pix0[1])).T, True)) patches.append(Polygon(np.vstack((pix1[0], pix1[1])).T, True)) data.append(self.data[i]) data.append(self.data[i]) else: polygon = Polygon(np.vstack((idx[0], idx[1])).T, True) patches.append(polygon) data.append(self.data[i]) p = PatchCollection(patches, linewidths=0, edgecolors="None") p.set_array(np.array(data)) ax.add_collection(p) ax.autoscale_view() ax.coords.grid(color="w", linestyle=":", linewidth=0.5) return fig, ax, p
def from_galfile(cls, filename, zredfile=None, nside=0, hpix=0, border=0.0, truth=False): """ Generate a GalaxyCatalog from a redmapper "galfile." Parameters ---------- filename: `str` Filename of the redmapper "galfile" galaxy file. This file may be a straight fits file or (recommended) a galaxy table "master_table.fit" summary file. zredfile: `str`, optional Filename of the redmapper zred "zreds_master_table.fit" summary file. nside: `int`, optional Nside of healpix sub-region to read in. Default is 0 (full catalog). hpix: `int`, optional Healpix number (ring format) of sub-region to read in. Default is 0 (full catalog). border: `float`, optional Border around hpix (in degrees) to read in. Default is 0.0. truth: `bool`, optional Read in truth information if available (e.g. mocks)? Default is False. """ if zredfile is not None: use_zred = True else: use_zred = False if hpix == 0: _hpix = None else: _hpix = hpix # do we have appropriate keywords if _hpix is not None and nside is None: raise ValueError("If hpix is specified, must also specify nside") if border < 0.0: raise ValueError("Border must be >= 0.0.") # ensure that nside is valid, and hpix is within range (if necessary) if nside > 0: if not hp.isnsideok(nside): raise ValueError("Nside not valid") if _hpix is not None: if _hpix < 0 or _hpix >= hp.nside2npix(nside): raise ValueError("hpix out of range.") # check that the file is there and the right format # this will raise an exception if it's not there. hdr = fitsio.read_header(filename, ext=1) pixelated = hdr.get("PIXELS", 0) fitsformat = hdr.get("FITS", 0) # check zredfile if use_zred: zhdr = fitsio.read_header(zredfile, ext=1) zpixelated = zhdr.get("PIXELS", 0) if not pixelated: cat = fitsio.read(filename, ext=1, upper=True) if use_zred: zcat = fitsio.read(zredfile, ext=1, upper=True) if zcat.size != cat.size: raise ValueError("zredfile is a different length (%d) than catfile (%d)" % (zcat.size, cat.size)) return cls(cat, zcat) else: return cls(cat) else: if use_zred: if not zpixelated: raise ValueError("galfile is pixelated but zredfile is not") # this is to keep us from trying to use old IDL galfiles if not fitsformat: raise ValueError("Input galfile must describe fits files.") # now we can read in the galaxy table summary file... tab = Entry.from_fits_file(filename, ext=1) nside_tab = tab.nside if nside > nside_tab: raise ValueError("""Requested nside (%d) must not be larger than table nside (%d).""" % (nside, nside_tab)) if use_zred: ztab = Entry.from_fits_file(zredfile, ext=1) zpath = os.path.dirname(zredfile) # which files do we want to read? path = os.path.dirname(os.path.abspath(filename)) indices = get_subpixel_indices(tab, hpix=_hpix, border=border, nside=nside) # Make sure all the zred files are there if use_zred: # The default mode, copied from the IDL code, is that we just don't # read in any galaxy pixels that don't have an associated zred. # I don't know if this is what we want going forward, but I'll leave # it like this at the moment. # Also, we are assuming that the files actually match up in terms of length, etc. mark = np.zeros(indices.size, dtype=np.bool) for i, f in enumerate(ztab.filenames[indices]): if os.path.isfile(os.path.join(zpath, f.decode())): mark[i] = True bad, = np.where(~mark) if bad.size == indices.size: raise ValueError("There are no zred files associated with the galaxy pixels.") indices = np.delete(indices, bad) # create the catalog array to read into # FIXME: filter out any TRUTH information if necessary # will need to also get the list of columns from the thingamajig. # and need to be able to cut? elt = fitsio.read(os.path.join(path, tab.filenames[indices[0]].decode()), ext=1, rows=0, lower=True) dtype_in = elt.dtype.descr if not truth: mark = [] for dt in dtype_in: if (dt[0] != 'ztrue' and dt[0] != 'm200' and dt[0] != 'central' and dt[0] != 'halo_id'): mark.append(True) else: mark.append(False) dtype = [dt for i, dt in enumerate(dtype_in) if mark[i]] columns = [dt[0] for dt in dtype] else: dtype = dtype_in columns = None cat = np.zeros(np.sum(tab.ngals[indices]), dtype=dtype) if use_zred: zelt = fitsio.read(os.path.join(zpath, ztab.filenames[indices[0]].decode()), ext=1, rows=0, upper=False) zcat = np.zeros(cat.size, dtype=zelt.dtype) # read the files ctr = 0 for index in indices: cat[ctr: ctr + tab.ngals[index]] = fitsio.read(os.path.join(path, tab.filenames[index].decode()), ext=1, lower=True, columns=columns) if use_zred: # Note that this effectively checks that the numbers of rows in each file match properly (though the exception will be cryptic...) zcat[ctr: ctr + tab.ngals[index]] = fitsio.read(os.path.join(zpath, ztab.filenames[index].decode()), ext=1, upper=False) ctr += tab.ngals[index] if _hpix is not None and nside > 0 and border > 0.0: # Trim to be closer to the border if necessary... nside_cutref = 512 boundaries = hp.boundaries(nside, hpix, step=nside_cutref/nside) theta, phi = hp.pix2ang(nside_cutref, np.arange(hp.nside2npix(nside_cutref))) ipring_coarse = hp.ang2pix(nside, theta, phi) inhpix, = np.where(ipring_coarse == hpix) for i in xrange(boundaries.shape[1]): pixint = hp.query_disc(nside_cutref, boundaries[:, i], np.radians(border), inclusive=True, fact=8) inhpix = np.append(inhpix, pixint) inhpix = np.unique(inhpix) theta = np.radians(90.0 - cat['dec']) phi = np.radians(cat['ra']) ipring = hp.ang2pix(nside_cutref, theta, phi) _, indices = esutil.numpy_util.match(inhpix, ipring) if use_zred: return cls(cat[indices], zcat[indices]) else: return cls(cat[indices]) else: # No cuts if use_zred: return cls(cat, zcat) else: return cls(cat)
def contour(m, levels, nest=False, degrees=False, simplify=True): import pkg_resources try: pkg_resources.require('healpy >= 1.9.0') except: raise RuntimeError('This function requires healpy >= 1.9.0.') try: import networkx as nx except: raise RuntimeError('This function requires the networkx package.') # Determine HEALPix resolution npix = len(m) nside = hp.npix2nside(npix) min_area = 0.4 * hp.nside2pixarea(nside) # Compute faces, vertices, and neighbors. # vertices is an N X 3 array of the distinct vertices of the HEALPix faces. # faces is an npix X 4 array mapping HEALPix faces to their vertices. # neighbors is an npix X 4 array mapping faces to their nearest neighbors. faces = np.ascontiguousarray( np.rollaxis(hp.boundaries(nside, np.arange(npix), nest=nest), 2, 1)) dtype = faces.dtype faces = faces.view(np.dtype((np.void, dtype.itemsize * 3))) vertices, faces = np.unique(faces.ravel(), return_inverse=True) faces = faces.reshape(-1, 4) vertices = vertices.view(dtype).reshape(-1, 3) neighbors = hp.get_all_neighbours(nside, np.arange(npix), nest=nest)[::2].T # Loop over the requested contours. paths = [] for level in levels: # Find credible region indicator = (m >= level) # Construct a graph of the eges of the contour. graph = nx.Graph() face_pairs = set() for ipix1, ipix2 in enumerate(neighbors): for ipix2 in ipix2: # Determine if we have already considered this pair of faces. new_face_pair = frozenset((ipix1, ipix2)) if new_face_pair in face_pairs: continue face_pairs.add(new_face_pair) # Determine if this pair of faces are on a boundary of the # credible level. if indicator[ipix1] == indicator[ipix2]: continue # Add all common edges of this pair of faces. i1 = np.concatenate((faces[ipix1], [faces[ipix1][0]])) i2 = np.concatenate((faces[ipix2], [faces[ipix2][0]])) edges1 = frozenset(frozenset(_) for _ in zip(i1[:-1], i1[1:])) edges2 = frozenset(frozenset(_) for _ in zip(i2[:-1], i2[1:])) for edge in edges1 & edges2: graph.add_edge(*edge) graph = nx.freeze(graph) # Record a closed path for each cycle in the graph. cycles = [ np.take(vertices, cycle, axis=0) for cycle in nx.cycle_basis(graph)] # Simplify paths if requested if simplify: cycles = [_simplify(cycle, min_area) for cycle in cycles] cycles = [cycle for cycle in cycles if len(cycle) > 2] # Convert to lists cycles = [ _vec2radec(cycle, degrees=degrees).tolist() for cycle in cycles] # Add to output paths paths.append([cycle + [cycle[0]] for cycle in cycles]) return paths
def healpy_basemap_old(values,NSIDE=4,pixels=None,steps=4,vmin=None, vmax=None,projection='moll',figsize=(8,6), cmap='Blues',color='k',frame='galactic',marks=True, cbar=True,cbar_label=None,nest=_nest,alpha=1, cbar_orientation='horizontal',fig_m=None): """ """ if fig_m is None: fig, m = basic_basemap(projection=projection,figsize=figsize, color=color,frame=frame,marks=marks) else: fig, m = fig_m if pixels is None: pixels = range(hp.nside2npix(NSIDE)) if vmin is None: vmin = min(values) if vmax is None: vmax = max(values) if type(cmap) == str: cmap = plt.get_cmap(cmap) for pix,count in zip(pixels,values): corners = hp.boundaries(NSIDE,pix,step=steps,nest=nest) corners_b, corners_l = hp.vec2ang(np.transpose(corners)) l_raw = corners_l/_d2r l_edges = (corners_l/_d2r)%360 b_edges = 90 - corners_b/_d2r l_new = np.zeros((steps+1,steps+1)) b_new = np.zeros((steps+1,steps+1)) for new, old in zip([l_new,b_new],[l_edges,b_edges]): new[0,:] = old[:steps+1] new[1:,-1] = old[steps+1:2*steps+1] new[-1,-2::-1] = old[2*steps+1:3*steps+1] new[-2:0:-1,0] = old[3*steps+1:] for k in xrange(1,steps): new[k,:-1] = np.ones(steps)*new[k,0] count_arr = np.ones((steps+1,steps+1)) * count if np.sum((np.abs(l_new-180)<10).astype(int)) > 0: l_temp = np.fmin(l_new,179.9999) # Check that there are points not on the edges num_on_edges = np.sum(((l_temp != 179.9999) & (np.abs(b_new) != 90)).astype(int)) if num_on_edges > 0: x,y = m(l_temp,b_new) m.pcolor(x,y,count_arr,vmin=vmin,vmax=vmax,cmap=cmap,alpha=alpha) l_temp = np.fmax(l_new,180.0001) # Check that there are points not on the edges num_on_edges = np.sum(((l_temp != 180.0001) & (np.abs(b_new) != 90)).astype(int)) if num_on_edges > 0: x,y = m(l_temp,b_new) m.pcolor(x,y,count_arr,vmin=vmin,vmax=vmax,cmap=cmap,alpha=alpha) else: x,y = m(l_new,b_new) m.pcolor(x,y,count_arr,vmin=vmin,vmax=vmax,cmap=cmap,alpha=alpha) if not cbar: return fig, m else: cbar = plt.colorbar(orientation=cbar_orientation, shrink=0.92, pad=0.08) if cbar_label is not None: cbar.set_label(cbar_label, fontsize=20) return fig, m, cbar