def world2pix(wcs, x_world, y_world): if np.isscalar(x_world) and np.isscalar(y_world): x_pix, y_pix = wcs.wcs_world2pix(np.array([x_world]), np.array([y_world]), 1) return x_pix[0], y_pix[0] elif (type(x_world) == list) and (type(y_world) == list): x_pix, y_pix = wcs.wcs_world2pix(np.array(x_world), np.array(y_world), 1) return x_pix.tolist(), y_pix.tolist() elif isinstance(x_world, np.ndarray) and isinstance(y_world, np.ndarray): return wcs.wcs_world2pix(x_world, y_world, 1) else: raise Exception("world2pix should be provided either with two scalars, two lists, or two numpy arrays")
def skydir_to_pix(skydir,wcs): """Convert skydir object to pixel coordinates.""" if 'RA' in wcs.wcs.ctype[0]: xpix, ypix = wcs.wcs_world2pix(skydir.ra.deg,skydir.dec.deg,0) elif 'GLON' in wcs.wcs.ctype[0]: xpix, ypix = wcs.wcs_world2pix(skydir.galactic.l.deg,skydir.galactic.b.deg,0) else: raise Exception('Unrecognized WCS coordinate system.') return xpix,ypix
def world2pix(wcs, x_world, y_world): if np.isscalar(x_world) and np.isscalar(y_world): x_pix, y_pix = wcs.wcs_world2pix(np.array([x_world]), np.array([y_world]), 1) return x_pix[0], y_pix[0] elif (type(x_world) == list) and (type(y_world) == list): x_pix, y_pix = wcs.wcs_world2pix(np.array(x_world), np.array(y_world), 1) return x_pix.tolist(), y_pix.tolist() elif isinstance(x_world, np.ndarray) and isinstance(y_world, np.ndarray): return wcs.wcs_world2pix(x_world, y_world, 1) else: raise Exception( "world2pix should be provided either with two scalars, two lists, or two numpy arrays" )
def fit_cdmatrix(x, y, lon, lat, hdr): """Fit a CD matrix for a set of points with known pixel and world coordinates. The world coordinates are transformed to projection plane coordinates for a given projection, and then a 2d least squares fitting method is used to determine the best-fit CD matrix that transforms the pixel coordinates into projection plane coordinates. Parameters ---------- x, y : ndarray x and y pixel coordinates. lon, lat : ndarray Celestial longitude and latitude (world) coordinates. hdr : astropy.io.fits.Header A FITS header. Required keywords: - CTYPE1, CTYPE2 - CRPIX1, CRPIX2 - CRVAL1, CRVAL2 Returns ------- ndarray The best-fit CD matrix, ``[[CD1_1, CD1_2], [CD2_1, CD2_2]]``. """ def residuals(p, dx, dy, ip): # i represents x or y; # xp - (cd11*dx + cd12*dy) and yp - (cd21*dx + cd22*dy) cdi1, cdi2 = p err = ip - (cdi1*dx + cdi2*dy) return err # Calculate projection plane coords Converting celestial coordinates # into pixel coordinates involves 1) celestial spherical to native # spherical, 2) native spherical to projection plane, and 3) projection # plane to pixel. Steps 1 and 2 depend on the CTYPEi and CRVALi. Step 3 # depends on CDi_j and CRPIXi. All are known except CDi_j. By setting # the CD matrix to a unity matrix, the `wcs_world2pix` method converts # celestial coordinates through step 2 to projection plane coordinates. # The CD matrix can then be fit because the coordinates before and # after step 3 are known. wcs = astropy.wcs.WCS(hdr) wcs.wcs.cd = np.array([[1, 0], [0, 1]]) xp, yp = wcs.wcs_world2pix(lon, lat, 1) xp, yp = xp - hdr['CRPIX1'], yp - hdr['CRPIX2'] # Solve for CD elements dx, dy = x - hdr['CRPIX1'], y - hdr['CRPIX2'] p_init1 = (1, 0) p_init2 = (0, 1) args1 = (dx.ravel(), dy.ravel(), xp.ravel()) args2 = (dx.ravel(), dy.ravel(), yp.ravel()) cd11, cd12 = scipy.optimize.leastsq(residuals, p_init1, args=args1)[0] cd21, cd22 = scipy.optimize.leastsq(residuals, p_init2, args=args2)[0] return np.array([[cd11, cd12], [cd21, cd22]])
def _wcs_topixel (wcs, world, wcscale, naxis): world = np.asarray (world) if world.shape != (naxis, ): raise ValueError ('world coordinate must be a %d-element vector', naxis) world = (world / wcscale)[::-1].reshape ((1, naxis)) pixel = wcs.wcs_world2pix (world, 0) return pixel[0,::-1]
def _wcs_topixel(wcs, world, wcscale, naxis): world = np.asarray(world) if world.shape != (naxis, ): raise ValueError('world coordinate must be a %d-element vector', naxis) world = (world / wcscale)[::-1].reshape((1, naxis)) pixel = wcs.wcs_world2pix(world, 0) return pixel[0, ::-1]
def convert_ifuslot_xy_to_new_xy(self, x, y, wcs): ''' Fplane functionality required for this ''' if self.tp_ifuslot is None or not pyhetdex_flag: self.log.error('You have not setup the ifuslot projection yet.') self.log.error('To do so, call ' '"get_ifuslot_projection(ifuslot, imscale') return None ra, dec = self.tp_ifuslot.wcs.wcs_pix2world(x, y, 1) return wcs.wcs_world2pix(ra, dec, 1)
def SpatialSpectralMask(integrations, mask=None, wcs=None, off_frac=0.25, floatvalues=False, offpct=50, **kwargs): scanshape = integrations.data['DATA'].shape # Nscans x Nchans OffMask = np.array(scanshape, dtype=np.bool) freq = ((np.linspace(1, scanshape[1], scanshape[1])[np.newaxis, :] - integrations.data['CRPIX1'][:, np.newaxis]) * integrations.data['CDELT1'][:, np.newaxis] + integrations.data['CRVAL1'][:, np.newaxis]) x, y, z = wcs.wcs_world2pix(integrations.data['CRVAL2'][:, np.newaxis], integrations.data['CRVAL3'][:, np.newaxis], freq, 0) y = np.clip(y, 0, mask.shape[1] - 1) x = np.clip(x, 0, mask.shape[2] - 1) z = np.clip(z, 0, mask.shape[0] - 1) badx = ~np.isfinite(x) bady = ~np.isfinite(y) badz = ~np.isfinite(z) x[badx] = 0 y[bady] = 0 z[badz] = 0 # OffMask = True where OFF the galaxy) if floatvalues: OffEmission = np.array(mask[z.astype(np.int), y.astype(np.int), x.astype(np.int)], dtype=np.float) OffMask = OffEmission > 0 EmScans = np.sum(OffEmission, axis=1) BetterScans = (EmScans <= np.percentile(EmScans, offpct)) OffMask = (BetterScans[:, np.newaxis] * np.ones( (1, OffEmission.shape[1]), dtype=np.bool)) # blank_chans = np.all(OffEmission == 0, axis=0) AllOn = np.all(~OffMask, axis=0) else: OffMask = np.array(mask[z.astype(np.int), y.astype(np.int), x.astype(np.int)], dtype=np.bool) OffMask = ~OffMask AllOn = np.all(~OffMask, axis=0) # mask[x.astype(np.int)[badx], y.astype(np.int)[bady]] = False if np.any(AllOn): warnings.warn("Some channels always on emission") OffMask[:, AllOn] = True return (OffMask, 'SpatialSpectralMask') return (OffMask, 'SpatialSpectralMask')
def xy_th(BSCatalogue, wcs, data, edge=250, hdr=None): ''' Нахождение прямоугольных координат (x, y) на снимке для звёзд каталога без учёта дисторсии. ''' BSCatalogue.add_column(Column(np.zeros(len(BSCatalogue))), name='x') BSCatalogue.add_column(Column(np.zeros(len(BSCatalogue))), name='y') BSCatalogue.add_column(Column(np.zeros(len(BSCatalogue))), name='ch') a, b = len(data[0]), len(data) for i in BSCatalogue: if hdr is not None: xt, yt = wcs.wcs_world2pix(i['ra'], i['dec'], 0) obs = ascii.read('BSCatalogue_calibrate.csv', format='csv', fast_reader=False) if i['name'] in obs['name']: i['x'], i['y'] = xt, yt else: x, y = real_xy(xt, yt, hdr=hdr) i['x'], i['y'], i['ch'] = x, y, 1 else: i['x'], i['y'] = wcs.wcs_world2pix(i['ra'], i['dec'], 0) return BSCatalogue
def radec_to_xy(wcs, ra_dec): ''' Convert the ra/dec coordinates of a celestial body into the x/y coordinates of an image pixel. :param wcs: a wcs object, as returned by get_wcs() :param ra_dec: an instance of RaDec :return: an instance of PixelXL ''' coord = np.array([ [ra_dec.ra, ra_dec.dec], ], np.float_) result = wcs.wcs_world2pix(coord, 0) return PixelXY(x=result[0][0], y=result[0][1])
def skyPA(self): """ Finds the North by checking two points plus/minus a small angle from decDeg. And East is 90 deg from North. Returns North, East in degrees """ raDeg, decDeg = self.raDeg, self.decDeg smallAng = 100.0 / 3600.0 decDeg1 = decDeg + smallAng raDeg1 = raDeg + smallAng wcs = self.wcs x0, y0 = wcs.wcs_world2pix([raDeg], [decDeg], 0) x1, y1 = wcs.wcs_world2pix([raDeg], [decDeg1], 0) x2, y2 = wcs.wcs_world2pix([raDeg1], [decDeg], 0) north = math.degrees(math.atan2(y1 - y0, x1 - x0)) east = math.degrees(math.atan2(y2 - y0, x2 - x0)) return north, east
def maskLookup(ra, dec, freq): xx, yy, zz = wcs.wcs_world2pix(ra, dec, freq, 0) if (0 <= xx[0] < spatial_mask.shape[1] and 0 <= yy[0] < spatial_mask.shape[0]): emission = spatial_mask[int(yy[0]), int(xx[0])] else: emission = False if emission: zz = np.array(nuinterp(freq), dtype=np.int) zz[zz < 0] = 0 zz[zz >= mask.shape[0]] = mask.shape[0] - 1 return (mask[zz, yy.astype(np.int), xx.astype(np.int)]) else: return (np.zeros_like(freq, dtype=np.bool))
def nearest_neighbor_wcs(wcs, img, wcs_new): """ Generate image according to new wcs no interpolation is done. """ img_new = zeros([wcs_new.naxis2, wcs_new.naxis1]) for irow, row in enumerate(img_new): for icol, pix in enumerate(row): ra, dec = wcs_new.wcs_pix2world(icol, irow, 1) iicol, iirow = wcs.wcs_world2pix(ra, dec, 1) iicol, iirow = int(iicol), int(iirow) try: img_new[irow, icol] = img[iirow, iicol].copy() except IndexError: img_new[irow, icol] = -1 return img_new
def radec_to_xy(data, wcs=None, **kwargs): """Converts ``(RA, Dec)`` to ``(x, y)`` for a given GFA. Creates a mock WCS transformation for a given GFA and converts star RA, Dec to x, y on what would be a GFA image. This conversion is not carefully done and is not a proper transformation between on-sky coordinates and focal coordinates, but should be sufficient for the purposes of the simulation. Parameters ---------- data : pandas.DataFrame A dataframe with the star data. Must contain at least two columns, ``ra`` and ``dec``, in degrees. wcs : ~astropy.wcs.WCS The WCS object to use. If `None`, it calls `.create_gfa_wcs`. kwargs : dict Arguments to pass to `.create_gfa_wcs`. Returns ------- `~pandas.DataFrame`, `~astropy.wcs.WCS` The input dataframe with two columns, ``x`` and ``y`` indicating the position of the star on the GFA chip, and the `~astropy.wcs.WCS` object. """ if len(data) == 0: data['x'] = numpy.nan data['y'] = numpy.nan return data if not wcs: wcs = create_gfa_wcs(**kwargs) # Convert coordinates to x, y coords = data[['ra', 'dec']].to_numpy() x, y = wcs.wcs_world2pix(coords, 0).T data['x'] = x data['y'] = y return data, wcs
def ang2msk(lon, lat): maskfiles = sorted(glob.glob(DATADIR + '/W4*_izrgu_finalmask_mosaic.fits')) values = np.zeros(len(lon), dtype=int) index = np.arange(len(lon), dtype=int) warnings.simplefilter('ignore', category=astropy.wcs.FITSFixedWarning) idxs = [] for f in maskfiles: logging.debug(f) mask = fitsio.read(f) wcs = astropy.wcs.WCS(f) crval = wcs.wcs.crval radius = max(wcs.wcs.cdelt * np.array([wcs._naxis1, wcs._naxis2])) xpix, ypix = wcs.wcs_world2pix(lon, lat, 0) xedge = np.where(mask[wcs._naxis1 / 2, :] < EDGE)[0] yedge = np.where(mask[:, wcs._naxis2 / 2] < EDGE)[0] XMIN, XMAX = xedge.min(), xedge.max() YMIN, YMAX = yedge.min(), yedge.max() sel = (xpix > XMIN) & (xpix < XMAX) sel &= (ypix > YMIN) & (ypix < YMAX) xpix = xpix[sel].astype(int) ypix = ypix[sel].astype(int) idx = index[sel] idxs.append(idx) val = mask[ypix, xpix] values[idx] |= val # Set objects outside the footprint to EDGE idxs = np.hstack(idxs) idx = index[~np.in1d(index, idxs)] values[idx] = EDGE return values
def Stars_on_image(BSCatalogue, data_obs, wcs=None, CRIT_m=5.): ''' Фильтр звёзд, проходят только с (x, y) внутри изображения и m меньше заданной в главной части программы. Непрошедшие звёзды удаляются из каталога. ''' a, b = len(data_obs[0]), len(data_obs) i = 0 while i < len(BSCatalogue): x, y = BSCatalogue[i]['x'], BSCatalogue[i]['y'] m = BSCatalogue[i]['vmag'] if math.isnan(x) or math.isnan(y) or (x <= 0 or x >= a) or (y <= 0 or y >= b) or (m > CRIT_m): BSCatalogue.remove_row(i) i -= 1 else: if wcs is not None and BSCatalogue[i]['ch'] == 1: xt, yt = wcs.wcs_world2pix( BSCatalogue[i]['ra'], BSCatalogue[i]['dec'], 0) BSCatalogue[i]['x'], BSCatalogue[i]['y'] = xt, yt i += 1 return BSCatalogue
# objidからfitsファイルを特定する情報を取り出す params = unwrap_objid(objid) run = str(params['run']) camcol = str(params['camcol']) frame = str(params['frame']) # objidの銀河が含まれるfitsファイルを開く fits = astropy.io.fits.open('data/fits/fpC-' + run.zfill(6) + '-r' + camcol + '-' + frame.zfill(4) + '.fit.gz') data = fits[0].data header = fits[0].header # fitsファイルのheaderと銀河のra, decから, # 画像内の座標を得る wcs = astropy.wcs.WCS(header) px, py = wcs.wcs_world2pix(ra_deg, dec_deg, 0) px = int(px) py = int(py) # 得られた座標を中心として画像を切り出し、保存する r = 50 img_galaxy = data[py - r:py + r, px - r:px + r] plt.title('RA = {}, Dec = {}'.format(ra_hms, dec_hms)) plt.imshow(np.log10(img_galaxy.T[::-1, ::-1]), cmap='gray', vmin=3.05, vmax=3.09) # 画像上で5秒角に対応する長さの線を描画する cd1_2 = header['CD1_2'] pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / cd1_2)
def rd2xy(self, wcs, ra, dec): """ Transform input sky positions into pixel positions in the WCS provided. """ return wcs.wcs_world2pix(ra, dec, 1)
min_ra, max_ra = numpy.min(cand['sex'][:,0]), numpy.max(cand['sex'][:,0]) min_dec, max_dec = numpy.min(cand['sex'][:,1]), numpy.max(cand['sex'][:,1]) cos_dec = numpy.cos(numpy.radians(numpy.max(numpy.fabs(cand['sex'][:,1])))) ra_width = margin / 60. / cos_dec dec_width = margin / 60. corners = [[min_ra - ra_width, min_dec - dec_width], [min_ra - ra_width, max_dec + dec_width], [max_ra + ra_width, min_dec - dec_width], [max_ra + ra_width, max_dec + dec_width], ] print corners corners_xy = wcs.wcs_world2pix(corners, 0) corner_min = numpy.floor(numpy.min(corners_xy, axis=0)).astype(numpy.int) corner_max = numpy.ceil(numpy.max(corners_xy, axis=0)).astype(numpy.int) print wcs print corners print corners_xy print "corner min/max", corner_min, corner_max print "\n"*10,name,"\n"*10 # Now open each of the input files, and extract the sub-image for infile in inputlist: inhdu = astropy.io.fits.open(infile) data = inhdu[0].data.T
else: rad = float(0.5 * 16.6 + (1.27 * z)) chandra_r.append(rad) wcs = wcs.WCS(naxis=2) wcs.wcs.crpix = [25921, 25921] # sky (x,y) pixel coordinate referece pixel wcs.wcs.cdelt = np.array([-1.38888889e-05, 1.38888889e-05]) # pixel size 0.05" wcs.wcs.crval = [float(cra), float(cdec)] # (ra,dec) value at reference pixel wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN'] num = len(chandra_ra) x = np.zeros((num)) y = np.zeros((num)) r = np.zeros((num)) for i in range(0, num): skycoord = np.array([[chandra_ra[i], chandra_dec[i]]]) pixcoord = wcs.wcs_world2pix(skycoord, 1) radius = chandra_r[i] / 0.05 x[i] = pixcoord[0][0] y[i] = pixcoord[0][1] r[i] = radius # print "circle(",pixcoord[0][0],",",pixcoord[0][1],",",radius,")" data2 = np.recarray((num, ), dtype=(numpy.record, [('TYPE', 'S16'), ('X', '>f4', (4, )), ('Y', '>f4', (4, )), ('R', '>f4', (4, )), ('FLUX', '>f4', (1, )), ('ROTANG', '>f4', (4, ))])) for i in range(0, num): #if chandra_type[i] == 'GALAXY': data2[i][0] = chandra_type[i]
def main(): gz_table = Table.read('GalaxyZoo1_DR_table2.fits') # Galaxy Zooの表の上から 1000行目までを順に取り出す for galaxy_info in gz_table[:1000]: # Galaxy Zooの表からobjid, ra, decを取り出す objid = galaxy_info[0] ra_hms = galaxy_info[1] dec_hms = galaxy_info[2] # ra,decを60進数から10進数に変換 c = SkyCoord(ra_hms + ' ' + dec_hms, unit=(u.hourangle, u.deg)) ra_deg = c.ra.degree dec_deg = c.dec.degree # objidからfitsファイルを特定する情報を取り出す params = unwrap_objid(objid) run = str(params['run']) camcol = str(params['camcol']) frame = str(params['frame']) # objidの銀河が含まれるfitsファイルを開く fits = astropy.io.fits.open('../' + run.zfill(6) + '/fpC-' + run.zfill(6) + '-r' + camcol + '-' + frame.zfill(4) + '.fit.gz') data = fits[0].data header = fits[0].header # fitsファイルのheaderと銀河のra, decから, # 画像内の座標を得る wcs = astropy.wcs.WCS(header) px, py = wcs.wcs_world2pix(ra_deg, dec_deg, 0, ra_dec_order=True) px = int(px) py = int(py) # 得られた座標を中心として画像を切り出し、保存する r = 30 img_galaxy = data[py - r:py + r, px - r:px + r] plt.title('RA = {}, Dec = {}'.format(ra_hms, dec_hms)) plt.imshow(np.log10(img_galaxy.T[::-1, ::-1]), cmap='gray', vmin=3.05, vmax=3.09) # 画像上で5秒角に対応する長さの線を描画する if header['CTYPE1'] == 'DEC--TAN': pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / header['cd1_1']) else: pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / header['cd1_2']) # cd1_2 = abs(header['CD1_2']) # pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / cd1_2) plt.hlines(y=17, xmin=10, xmax=10 + pix_corresponding_to_5s) plt.savefig('data/img/' + str(objid), bbox_inches='tight') plt.close() # 画像をnpyで保存する np.save('data/npz/' + str(objid), img_galaxy) # 画像とGalaxy Zooのデータをnpzで保存する #np.savez('data/npz/' + str(objid), img_galaxy, galaxy_info) # img = Image.fromarray(np.uint8(fits[0].data[py-r:py+r, px-r:px+r])) csv_obj.close()
cutouts[freq] = {} mpfits[freq] = {} gpars[freq] = {} gparerrs[freq] = {} gfits[freq] = {} reg_centers[freq] = {} data = fits.getdata(fn).squeeze() header = flatten_header(fits.getheader(fn)) wcs = astropy.wcs.WCS(header).sub([astropy.wcs.WCSSUB_CELESTIAL]) beam = radio_beam.Beam.from_fits_header(header) beams[freq] = beam frequencies[freq] = header.get('CRVAL3') or header.get('ACRVAL3') if wcs.wcs.radesys == 'FK4' or wcs.wcs.equinox == 1950: (blx,bly),(tr_x,tr_y) = wcs.wcs_world2pix([(290.35090,14.42627),(290.34560,14.43126),],0) else: (blx,bly),(tr_x,tr_y) = wcs.wcs_world2pix([(290.92445,14.524376),(290.91912,14.529338)],0) error[freq] = data[bly:tr_y,blx:tr_x].std() obsdate[freq] = fits.getheader(fn)['DATE-OBS'] print("file: {0}".format(fn)) for reg in ProgressBar(reglist): name = reg.attr[1]['text'] if name in peaks[freq]: continue if reg.name == 'circle': ra,dec,rad = reg.coord_list elif reg.name == 'point':
# -*- coding: utf-8 -*- """ Created on Tue Jan 28 21:03:38 2020 https://qiita.com/nishimuraatsushi/items/f422c624027dcd34b820 @author: PC """ import astropy.wcs import astropy.io.fits fits = astropy.io.fits.open( 'http://www.astro.s.osakafu-u.ac.jp/~nishimura/Orion/data/Orion.CO1221.Osaka.beam204.mom0.fits.gz' ) wcs = astropy.wcs.WCS(fits[0].header) print(wcs) # WCS[geg]→画像座標系[pix]変換 print(wcs.wcs_world2pix([[215, -13.0]], 0)) print(wcs.wcs_world2pix([[214, -13.2]], 0)) print(wcs.wcs_world2pix([[213, -13.4]], 0)) print(wcs.wcs_world2pix([[212, -13.6]], 0)) print(wcs.wcs_world2pix([[211, -13.8]], 0)) print(wcs.wcs_world2pix([[210, -14.0]], 0)) print(wcs.wcs_world2pix([[209, -14.2]], 0)) print(wcs.wcs_world2pix([[208, -14.4]], 0)) print(wcs.wcs_world2pix([[207, -14.6]], 0))
def cut_fits_downloaded(filename, xc, yc, xw=1, yw=1, units='pixels', outfile=None, clobber=True, useMontage=False, coordsys='celestial', verbose=False): """ credit: http://code.google.com/p/agpy/source/browse/trunk/agpy/cutout.py changed by Hongquan on 25 May 2015: move the imports into the defination part Generate a cutout image from a .fits file Inputs: file - .fits filename or pyfits HDUList (must be 2D) xc,yc - x and y coordinates in the fits files' coordinate system (CTYPE) xw,yw - x and y width (pixels or wcs); xw and yw is half width of the output file units - specify units to use: either pixels or wcs outfile - optional output file """ try: import astropy.io.fits as pyfits import astropy.wcs as pywcs except ImportError: import pyfits import pywcs import numpy try: import coords except ImportError: pass # maybe should do something smarter here, but I want agpy to install... try: import montage_wrapper as montage import os CanUseMontage=True except ImportError: CanUseMontage=False class DimensionError(ValueError): pass if isinstance(filename,str): file = pyfits.open(filename) opened=True elif isinstance(filename,pyfits.HDUList): file = filename opened=False else: raise Exception("cutout: Input file is wrong type (string or HDUList are acceptable).") head = file[0].header.copy() if head['NAXIS'] > 2: raise DimensionError("Too many (%i) dimensions!" % head['NAXIS']) cd1 = head.get('CDELT1') if head.get('CDELT1') else head.get('CD1_1') cd2 = head.get('CDELT2') if head.get('CDELT2') else head.get('CD2_2') if cd1 is None or cd2 is None: raise Exception("Missing CD or CDELT keywords in header") wcs = pywcs.WCS(head) if units == 'wcs': if coordsys=='celestial' and wcs.wcs.lngtyp=='GLON': xc,yc = coords.Position((xc,yc),system=coordsys).galactic() elif coordsys=='galactic' and wcs.wcs.lngtyp=='RA': xc,yc = coords.Position((xc,yc),system=coordsys).j2000() if useMontage and CanUseMontage: head['CRVAL1'] = xc head['CRVAL2'] = yc if units == 'pixels': head['CRPIX1'] = xw head['CRPIX2'] = yw head['NAXIS1'] = int(xw*2) head['NAXIS2'] = int(yw*2) elif units == 'wcs': cdelt = numpy.sqrt(cd1**2+cd2**2) head['CRPIX1'] = xw / cdelt head['CRPIX2'] = yw / cdelt head['NAXIS1'] = int(xw*2 / cdelt) head['NAXIS2'] = int(yw*2 / cdelt) head.toTxtFile('temp_montage.hdr',clobber=True) newfile = montage.wrappers.reproject_hdu(file[0],header='temp_montage.hdr',exact_size=True) os.remove('temp_montage.hdr') else: xx,yy = wcs.wcs_world2pix(xc,yc,0) if units=='pixels': xmin,xmax = numpy.max([0,xx-xw]),numpy.min([head['NAXIS1'],xx+xw]) ymin,ymax = numpy.max([0,yy-yw]),numpy.min([head['NAXIS2'],yy+yw]) elif units=='wcs': xmin,xmax = numpy.max([0,xx-xw/numpy.abs(cd1)]),numpy.min([head['NAXIS1'],xx+xw/numpy.abs(cd1)]) ymin,ymax = numpy.max([0,yy-yw/numpy.abs(cd2)]),numpy.min([head['NAXIS2'],yy+yw/numpy.abs(cd2)]) else: raise Exception("Can't use units %s." % units) if xmax < 0 or ymax < 0: raise ValueError("Max Coordinate is outside of map: %f,%f." % (xmax,ymax)) if ymin >= head.get('NAXIS2') or xmin >= head.get('NAXIS1'): raise ValueError("Min Coordinate is outside of map: %f,%f." % (xmin,ymin)) head['CRPIX1']-=xmin head['CRPIX2']-=ymin head['NAXIS1']=int(xmax-xmin) head['NAXIS2']=int(ymax-ymin) if head.get('NAXIS1') == 0 or head.get('NAXIS2') == 0: raise ValueError("Map has a 0 dimension: %i,%i." % (head.get('NAXIS1'),head.get('NAXIS2'))) img = file[0].data[ymin:ymax,xmin:xmax] newfile = pyfits.PrimaryHDU(data=img,header=head) if verbose: print("Cut image %s with dims %s to %s. xrange: %f:%f, yrange: %f:%f" % (filename, file[0].data.shape,img.shape,xmin,xmax,ymin,ymax)) if isinstance(outfile,str): newfile.writeto(outfile,clobber=clobber) if opened: file.close() return newfile
def convertCoords(coords, mode='sky', wcs=None, xyorig='center', shape=None): """Converts input coordinates to array indices. Converts input positions in x, y or RA, Dec coordinates to array indices (in Numpy style) or spaxel extraction. In case of pixel coordinates, the origin of reference (either the center of the cube or the lower left corner) can be specified via ``xyorig``. If ``shape`` is defined (mandatory for ``mode='pix'``, optional for ``mode='sky'``) and one or more of the resulting indices are outside the size of the input shape, an error is raised. This functions is mostly intended for internal use. Parameters: coords (array): The input coordinates, as an array of shape Nx2. mode ({'sky', 'pix'}: The type of input coordinates, either `'sky'` for celestial coordinates (in the format defined in the WCS header information), or `'pix'` for pixel coordinates. wcs (None or ``astropy.wcs.WCS`` object): If ``mode='sky'``, the WCS solution from which the cube coordinates can be derived. xyorig (str): If ``mode='pix'``, the reference point from which the coordinates are measured. Valid values are ``'center'``, for the centre of the spatial dimensions of the cube, or ``'lower'`` for the lower-left corner. shape (None or array): If ``mode='pix'``, the shape of the spatial dimensions of the cube, so that the central position can be calculated. Returns: result (Numpy array): An array with the same shape as ``coords``, containing the cube index positions for the input coordinates, in Numpy style (i.e., the first element being the row and the second the column). """ coords = np.atleast_2d(coords) assert coords.shape[1] == 2, 'coordinates must be an array Nx2' if mode == 'sky': assert wcs, 'if mode==sky, wcs must be defined.' coordsSpec = np.ones((coords.shape[0], 3), np.float32) coordsSpec[:, :-1] = coords cubeCoords = wcs.wcs_world2pix(coordsSpec, 0) cubeCoords = np.fliplr(np.array(np.round(cubeCoords[:, :-1]), np.int)) elif mode in ['pix', 'pixel']: assert xyorig, 'if mode==pix, xyorig must be defined.' x = coords[:, 0] y = coords[:, 1] assert shape, 'if mode==pix, shape must be defined.' shape = np.atleast_1d(shape) if xyorig == 'center': yMid, xMid = shape / 2. xCube = np.round(xMid + x) yCube = np.round(yMid + y) elif xyorig == 'lower': xCube = np.round(x) yCube = np.round(y) else: raise ValueError('xyorig must be center or lower.') cubeCoords = np.array([yCube, xCube], np.int).T else: raise ValueError('mode must be pix or sky.') if shape is not None: if ((cubeCoords < 0).any() or (cubeCoords[:, 0] > (shape[0] - 1)).any() or (cubeCoords[:, 1] > (shape[1] - 1)).any()): raise MarvinError('some indices are out of limits.' '``xyorig`` is currently set to "{0}". ' 'Try setting ``xyorig`` to "{1}".'.format( xyorig, 'center' if xyorig is 'lower' else 'lower')) return cubeCoords
def app_phot(self, imagefile, ras, decs, fwhm, plot=False, save=False): ''' Computes the aperture photometry on the image, for the coordinates given. Parameters ---------- imagefile : str The name of the fits file with the image. ras : array Array of floats with the RA positions for which aperture photometry is needed. decs : array Array of floats with the DEC positions for which aperture photometry is needed. fwhm : float Average FWHM of the field used to compute the aperture. plot : boolean Shall the apertures be plotted in the plot directory? save : boolean Save the aperture measurement to a file. Returns ------- phot : QTable A table of the photometry with the following columns: 'id': The source ID. 'xcenter', 'ycenter': The x and y pixel coordinates of the input aperture center(s). 'celestial_center': 'aperture_sum': The sum of the values within the aperture. 'aperture_sum_err': The corresponding uncertainty in the 'aperture_sum' values. Returned only if the input error is not None. ''' data = fits.open(imagefile)[self.ext].data filt = fitsutils.get_par(imagefile, 'FILTER', self.ext) mjd = Time(fitsutils.get_par(imagefile, "DATE-OBS", ext=self.ext)).mjd zp = fitsutils.get_par(imagefile, 'ZP', self.ext) color = fitsutils.get_par(imagefile, 'COLOR', self.ext) kcoef = fitsutils.get_par(imagefile, 'KCOEF', self.ext) zperr = fitsutils.get_par(imagefile, 'ZPERR', self.ext) if zp is None: zp = 0 if zperr is None: zperr = 0 wcs = astropy.wcs.WCS(fits.open(imagefile)[self.ext].header) positions = SkyCoord(ras*u.deg, decs*u.deg, frame='icrs') # Set aperture radius to three times the fwhm radius aperture_rad = np.median(fwhm)*2* u.arcsec aperture = SkyCircularAperture(positions, r=aperture_rad) annulus_apertures = SkyCircularAnnulus(positions, r_in=aperture_rad*2, r_out=aperture_rad*4) #Convert to pixels pix_aperture = aperture.to_pixel(wcs) pix_annulus = annulus_apertures.to_pixel(wcs) pix_annulus_masks = pix_annulus.to_mask(method='center') #Plot apertures from astropy.visualization import simple_norm try: if np.ndim(ras) == 0: c = wcs.wcs_world2pix(np.array([[ras, decs]]), 0) else: c = wcs.wcs_world2pix(np.array([ras, decs]).T, 0) except ValueError: self.logger.error('The vectors of RAs, DECs could not be converted into pixels using the WCS!') self.logger.error(str(np.array([ras, decs]).T)) if plot: x = c[:,0] y = c[:,1] plt.figure(figsize=(10,10)) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) pix_aperture.plot(color='white', lw=2) pix_annulus.plot(color='red', lw=2) plt.xlim(x[0]-200, x[0]+200) plt.ylim(y[0]-200, y[0]+200) plt.title('Apertures for filter %s'%filt) plt.savefig(os.path.join(self._plotpath, "apertures_cutout_%s.png"%os.path.basename(imagefile))) plt.clf() #Divide each pixel in 5 subpixels to make apertures apers = [pix_aperture, pix_annulus] phot_table = aperture_photometry(data, apers, method='subpixel', subpixels=5) for col in phot_table.colnames: phot_table[col].info.format = '%.8g' # for consistent table output bkg_median = [] std_counts = [] for mask in pix_annulus_masks: annulus_data = mask.multiply(data) annulus_data_1d = annulus_data[mask.data > 0] _, median_sigclip, stdv_clip = sigma_clipped_stats(annulus_data_1d) bkg_median.append(median_sigclip) std_counts.append(stdv_clip) bkg_median = np.array(bkg_median) std_counts = np.array(std_counts) phot = aperture_photometry(data, pix_aperture) phot['annulus_median'] = bkg_median phot['annulus_std'] = std_counts phot['aper_bkg'] = bkg_median * pix_aperture.area() phot['aper_sum_bkgsub'] = phot['aperture_sum'] - phot['aper_bkg'] # Flux = Gain * Counts / Exptime. exptime = fitsutils.get_par(imagefile, 'EXPTIME', self.ext) gain = fitsutils.get_par(imagefile, self.gain_keyword, self.ext) flux = gain * phot['aper_sum_bkgsub'] / exptime inst_mag = -2.5*np.log10(flux) phot['flux'] = flux phot['inst_mag'] = inst_mag #Noise is the poisson noise of the source plus the background noise for the extracted area err = np.sqrt (flux + pix_aperture.area() * std_counts**2) #Transform pixels to magnitudes flux2 = gain * (phot['aper_sum_bkgsub']+err) / exptime inst_mag2 = -2.5*np.log10(flux2) errmag = np.abs(inst_mag2 - inst_mag) phot['err_counts'] = err phot['err_mag'] = errmag for col in phot.colnames: phot[col].info.format = '%.8g' # for consistent table output if save: appfile = os.path.join(self._photpath, fitsutils.get_par(imagefile, "OBJECT", self.ext)+".app.phot.txt") self.logger.info('Creating aperture photometry out file as %s'%appfile) #Save the photometry into a file if (not os.path.isfile(appfile)): with open(appfile, 'w') as f: f.write("mjd filter instr_mag zp zperr color kcoef mag magerr\n") with open(appfile, 'a') as f: self.logger.info('Adding aperture photometry to file %s'%appfile) f.write("%.3f %s %.4f %.4f %.4f %s %.4f %.4f %.4f\n"%(mjd, filt, phot['inst_mag'].data[0], \ zp, zperr, color, kcoef, phot['inst_mag'].data[0]+ zp, phot['err_mag'].data[0])) return phot
def main(): gz_table = Table.read('GalaxyZoo1_DR_table2.fits') # Galaxy Zooの表の上から i行目までを順に取り出す for galaxy_info in tqdm(gz_table[:15000]): # Galaxy Zooの表からobjid, ra, decを取り出す objid = galaxy_info[0] ra_hms = galaxy_info[1] dec_hms = galaxy_info[2] # ra,decを60進数から10進数に変換 c = SkyCoord(ra_hms + ' ' + dec_hms, unit=(u.hourangle, u.deg)) ra_deg = c.ra.degree dec_deg = c.dec.degree # objidからfitsファイルを特定する情報を取り出す params = unwrap_objid(objid) run = str(params['run']) camcol = str(params['camcol']) frame = str(params['frame']) # objidの銀河が含まれるfitsファイルを開く fits = astropy.io.fits.open('/home/homma/hdd/hdd2/data_set/r_bands/data_rbands/' + run.zfill(6) + '/fpC-' + run.zfill(6) + '-r' + camcol\ + '-' + frame.zfill(4) + '.fit.gz') data = fits[0].data header = fits[0].header # fitsファイルのheaderと銀河のra, decから, # 画像内の座標を得る wcs = astropy.wcs.WCS(header) px, py = wcs.wcs_world2pix(ra_deg, dec_deg, 0, ra_dec_order=True) px = int(px) py = int(py) # 得られた座標を中心として画像を切り出し、保存する r = 32 img_galaxy = data[py - r:py + r, px - r:px + r] plt.title('RA = {}, Dec = {}'.format(ra_hms, dec_hms)) plt.imshow(np.log10(img_galaxy.T[::-1, ::-1]), cmap='gray', vmin=3.05, vmax=3.09) # 画像上で5秒角に対応する長さの線を描画する if header['CTYPE1'] == 'DEC--TAN': pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / header['cd1_1']) else: pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / header['cd1_2']) # cd1_2 = abs(header['CD1_2']) # pix_corresponding_to_5s = round(DEG_CORRESPONDING_TO_5S / cd1_2) # printで確認 # if objid == 587724198813433876 or objid == 587724199349518483: # print(count,ra_deg,dec_deg,px, py, pix_corresponding_to_5s, header['CTYPE1']) plt.hlines(y=17, xmin=10, xmax=10 + pix_corresponding_to_5s) plt.savefig('data/img/' + str(objid), bbox_inches='tight') plt.close() # Tableの情報をcsvに保存する # 画像のnparray保存 np.save('data/npz/' + str(objid), img_galaxy)
def solve(self, scale): if not self.error and not self.is_solved: name, extension = os.path.splitext(self.filename) self.savePpm() scale_low = str(scale * 80.0 / 100.0) scale_high = str(scale * 120.0 / 100.0) subprocess.call([ "/usr/local/astrometry/bin/solve-field", "--downsample", "2", "--tweak-order", "2", "--scale-units", "arcsecperpix", "--scale-low", scale_low, "--scale-high", scale_high, "--no-plots", "--overwrite", name + ".ppm" ]) if os.path.isfile(name + '.solved'): correlation = astropy.io.fits.open(name + '.corr') self.correlation = correlation[1].data wcs = astropy.wcs.WCS( astropy.io.fits.open(name + '.new')[0].header) # Search for deep sky objects galaxy = astropy.io.fits.open( '/usr/local/astrometry/extra/ngc2000.fits') self.galaxy = numpy.empty((1000, 4), dtype=numpy.int) galaxy_num = 0 galaxy_scale = astropy.wcs.utils.proj_plane_pixel_scales( wcs).mean() for i in galaxy[1].data: galaxy_pix = wcs.wcs_world2pix(numpy.array([[i[1], i[2]]]), 1) if galaxy_pix[0][0] > 0 and galaxy_pix[0][ 0] < self.rgb16.shape[0] and galaxy_pix[0][ 1] > 0 and galaxy_pix[0][1] < self.rgb16.shape[ 1]: self.galaxy[galaxy_num, 0] = i[0] self.galaxy[galaxy_num, 1] = galaxy_pix[0][0] self.galaxy[galaxy_num, 2] = galaxy_pix[0][1] self.galaxy[galaxy_num, 3] = i[3] / galaxy_scale galaxy_num = galaxy_num + 1 self.galaxy = self.galaxy[0:galaxy_num] self.stars = numpy.empty((len(correlation[1].data), 3)) for i in range(0, len(correlation[1].data)): star_x = correlation[1].data[i][5] star_y = correlation[1].data[i][4] self.stars[i][0] = star_x self.stars[i][1] = star_y self.stars[i][2] = correlation[1].data[i][11] self.stars = self.stars[self.stars[:, 2].argsort()[::-1]] if self.stars.shape[0] > 20: self.stars = self.stars[0:20] self.is_solved = True try: os.remove(name + '-indx.xyls') os.remove(name + '.axy') os.remove(name + '.corr') os.remove(name + '.match') os.remove(name + '.new') os.remove(name + '.ppm') os.remove(name + '.rdls') os.remove(name + '.solved') os.remove(name + '.wcs') except: print " Some file was not here."
def get_finder(ra, dec, name, rad, debug=False, starlist=None, print_starlist=True, telescope="P200", directory=".", minmag=15, maxmag=18.5, mag=np.nan, image_file=None): ''' Creates a PDF with the finder chart for the object with the specified name and coordinates. It queries the PS1 catalogue to obtain nearby offset stars and get an R-band image as background. Parameters ---------- ra : float RA of our target in degrees. dec : float DEC of our target in degrees. name : str The name of your target rad : float Search radius for the finder in degrees. debug : bool (optional) Option to activate/ deactivate additional output. starlist : str (optional) Path/name of the file where the coordinates for the object are going to be saved. If the file exists, the content will be appended at the end. If no value is provided, the output just writes to the standard output (in case print_starlist is True). print_starlist : boolean (optional) Indicates if the starlist shall be printed in the standard output. telescope : str (optional) The current two values accepted are "Keck" and "P200". directory : str (optional) The directory where the PDF with the finder chart shall be stored. If no value given, the file will be store in the current directory where the script is run. minmag : float (optional) The minimum magnitud (brightest in this case) star that we would like to use as an offset star. maxmag : float (optional) The maximum magnitude (faintest) star that we would like to use as an offset star. mag : float or `None` (optional) The magnitude of our target. ''' try: ra = float(ra) dec = float(dec) except: ra, dec = hour2deg(ra, dec) if dec < -30: catalog = query_sky_mapper_catalogue(ra, dec, (rad / 2.) * 0.95, minmag=minmag, maxmag=maxmag) else: catalog = query_ps1_catalogue(ra, dec, (rad / 2.) * 0.95, minmag=minmag, maxmag=maxmag) if (debug): print(catalog) if (len(catalog) < 3): if debug: print("Looking for a bit fainter stars up to mag: %.2f" % (maxmag + 0.25)) catalog = query_ps1_catalogue(ra, dec, (rad / 2.) * 0.95, minmag=minmag, maxmag=maxmag + 0.5) if (len(catalog) < 3): print("Restarting with larger radius %.2f arcmin" % (rad * 60 + 0.5)) get_finder(ra, dec, name, rad + 0.5 / 60, directory=directory, minmag=minmag, maxmag=maxmag + 0.5, mag=mag, starlist=starlist, telescope=telescope) return if (not catalog is None and len(catalog) > 0): np.random.shuffle(catalog) no_self_object = (np.abs(catalog["ra"] - ra) * np.cos(np.deg2rad(dec)) > 2. / 3600) * (np.abs(catalog["dec"] - dec) > 2. / 3600) catalog = catalog[no_self_object] catalog.sort(order='mag') if (debug): print(catalog) if image_file is None: image_file = get_fits_image(ra, dec, rad, debug=debug) image = fits.open(image_file) else: image = fits.open(image_file) image = np.rot90(np.rot90(image)) if image_file is None or image is None: print("FATAL ERROR! Your FITS image could not be retrieved.") return # Get pixel coordinates of SN, reference stars in DSS image wcs = astropy.wcs.WCS(image[0].header) if (len(catalog) > 0): #w = astropy.wcs.find_all_wcs(ps1_image[0].header, relax=True, keysel=None)[0] ref1_pix = wcs.wcs_world2pix( np.array([[catalog["ra"][0], catalog["dec"][0]]], np.float_), 1) if (len(catalog) > 1): ref2_pix = wcs.wcs_world2pix( np.array([[catalog["ra"][1], catalog["dec"][1]]], np.float_), 1) #ref3_pix = wcs.wcs_world2pix(np.array([[catalog["ra"][2], catalog["dec"][2]]], np.float_), 1) target_pix = wcs.wcs_world2pix([(np.array([ra, dec], np.float_))], 1) # Plot finder chart #Adjust some of the counts to make easier the plotting. image[0].data[image[0].data > 30000] = 30000 image[0].data[np.isnan(image[0].data)] = 0 plt.figure(figsize=(8, 6)) plt.set_cmap('gray_r') smoothedimage = gaussian_filter(image[0].data, 1.3) plt.imshow(smoothedimage, origin='lower',vmin=np.percentile(image[0].data.flatten(), 10), \ vmax=np.percentile(image[0].data.flatten(), 99.0)) # Mark target plt.plot([target_pix[0, 0] + 15, (target_pix[0, 0] + 10)], [target_pix[0, 1], (target_pix[0, 1])], 'g-', lw=2) plt.plot([target_pix[0, 0], (target_pix[0, 0])], [target_pix[0, 1] + 10, (target_pix[0, 1]) + 15], 'g-', lw=2) plt.annotate(name, xy=(target_pix[0, 0], target_pix[0, 1]), xycoords='data', xytext=(22, -3), textcoords='offset points') # Mark and label reference stars if (len(catalog) > 0): plt.plot([ref1_pix[0, 0] + 15, (ref1_pix[0, 0] + 10)], [ref1_pix[0, 1], (ref1_pix[0, 1])], 'b-', lw=2) plt.plot([ref1_pix[0, 0], (ref1_pix[0, 0])], [ref1_pix[0, 1] + 10, (ref1_pix[0, 1]) + 15], 'b-', lw=2) plt.annotate("R1", xy=(ref1_pix[0, 0], ref1_pix[0, 1]), xycoords='data', xytext=(22, -3), textcoords='offset points', color="b") if (len(catalog) > 1): plt.plot([ref2_pix[0, 0] + 15, (ref2_pix[0, 0] + 10)], [ref2_pix[0, 1], (ref2_pix[0, 1])], 'r-', lw=2) plt.plot([ref2_pix[0, 0], (ref2_pix[0, 0])], [ref2_pix[0, 1] + 10, (ref2_pix[0, 1]) + 15], 'r-', lw=2) plt.annotate("R2", xy=(ref2_pix[0, 0], ref2_pix[0, 1]), xycoords='data', xytext=(22, -3), textcoords='offset points', color="r") # Set limits to size of DSS image pylab.xlim([0, (image[0].data.shape[0])]) pylab.ylim([0, (image[0].data.shape[1])]) # Plot compass plt.plot([(image[0].data.shape[0]) - 10, (image[0].data.shape[0] - 40)], [10, 10], 'k-', lw=2) plt.plot([(image[0].data.shape[0]) - 10, (image[0].data.shape[0]) - 10], [10, 40], 'k-', lw=2) plt.annotate("N", xy=((image[0].data.shape[0]) - 20, 40), xycoords='data', xytext=(-4, 5), textcoords='offset points') plt.annotate("E", xy=((image[0].data.shape[0]) - 40, 20), xycoords='data', xytext=(-12, -5), textcoords='offset points') # Set axis tics (not implemented correctly yet) plt.tick_params(labelbottom='off') plt.tick_params(labelleft='off') plt.axes().xaxis.set_major_locator(MaxNLocator(5)) plt.axes().yaxis.set_major_locator(MaxNLocator(5)) plt.axes().set_xlabel('%.1f\'' % (rad * 60)) plt.axes().set_ylabel('%.1f\'' % (rad * 60)) # Set size of window (leaving space to right for ref star coords) plt.subplots_adjust(right=0.65, left=0.05, top=0.99, bottom=0.05) #If no magnitude was supplied, just do not put it on the chart. if not np.isnan(mag): target_mag = "mag=%.2f" % mag else: target_mag = "" # List name, coords, mag of references etc plt.text(1.02, 0.85, name, transform=plt.axes().transAxes, fontweight='bold') plt.text(1.02, 0.80, "%s" % target_mag, transform=plt.axes().transAxes, fontweight='bold') plt.text(1.02, 0.75, "%.5f %.5f" % (ra, dec), transform=plt.axes().transAxes) rah, dech = deg2hour(ra, dec) plt.text(1.02, 0.7, rah + " " + dech, transform=plt.axes().transAxes) #Put the text for the offset stars. if (len(catalog) > 0): ofR1 = get_offset(catalog["ra"][0], catalog["dec"][0], ra, dec) S1 = deg2hour(catalog["ra"][0], catalog["dec"][0], sep=":") plt.text(1.02, 0.60, 'R1, mag=%.2f' % catalog["mag"][0], transform=plt.axes().transAxes, color="b") plt.text(1.02, 0.55, '%s %s' % (S1[0], S1[1]), transform=plt.axes().transAxes, color="b") plt.text(1.02, 0.5, "E: %.2f N: %.2f" % (ofR1[0], ofR1[1]), transform=plt.axes().transAxes, color="b") if (len(catalog) > 1): ofR2 = get_offset(catalog["ra"][1], catalog["dec"][1], ra, dec) S2 = deg2hour(catalog["ra"][1], catalog["dec"][1], sep=":") plt.text(1.02, 0.4, 'R2, mag=%.2f' % catalog["mag"][1], transform=plt.axes().transAxes, color="r") plt.text(1.02, 0.35, '%s %s' % (S2[0], S2[1]), transform=plt.axes().transAxes, color="r") plt.text(1.02, 0.3, "E: %.2f N: %.2f" % (ofR2[0], ofR2[1]), transform=plt.axes().transAxes, color="r") # Save to pdf pylab.savefig(os.path.join(directory, str(name + '_finder.pdf'))) if debug: print("Saved to %s" % os.path.join(directory, str(name + '_finder.pdf'))) pylab.close("all") #Print starlist if telescope == "Keck": commentchar = "#" separator = "" else: commentchar = "!" separator = "!" if (len(catalog) > 0 and (print_starlist or not starlist is None)): print("{0} {2} {3} 2000.0 {1} ".format(name.ljust(20), commentchar, *deg2hour(ra, dec, sep=" "))) S1 = deg2hour(catalog["ra"][0], catalog["dec"][0], sep=" ") print( "{:s} {:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} r={:.1f} {:s} " .format((name + "_S1").ljust(20), S1[0], S1[1], separator, ofR1[0], ofR1[1], catalog["mag"][0], commentchar)) if (len(catalog) > 1 and (print_starlist or not starlist is None)): S2 = deg2hour(catalog["ra"][1], catalog["dec"][1], sep=" ") print( "{:s} {:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} r={:.1f} {:s} " .format((name + "_S2").ljust(20), S2[0], S2[1], separator, ofR2[0], ofR2[1], catalog["mag"][1], commentchar)) r, d = deg2hour(ra, dec, sep=" ") #Write to the starlist if the name of the starlist was provided. if (not starlist is None) and (telescope == "Keck"): with open(starlist, "a") as f: f.write("{0} {1} {2} 2000.0 # {3} \n".format( name.ljust(17), r, d, target_mag)) if (len(catalog) > 0): f.write( "{:s} {:s} {:s} 2000.0 raoffset={:.2f} decoffset={:.2f} r={:.1f} # \n" .format((name + "_S1").ljust(17), S1[0], S1[1], ofR1[0], ofR1[1], catalog["mag"][0])) if (len(catalog) > 1): f.write( "{:s} {:s} {:s} 2000.0 raoffset={:.2f} decoffset={:.2f} r={:.1f} # \n" .format((name + "_S2").ljust(17), S2[0], S2[1], ofR2[0], ofR2[1], catalog["mag"][1])) f.write('\n') if (not starlist is None) and (telescope == "P200"): with open(starlist, "a") as f: f.write("{0} {1} {2} 2000.0 ! {3}\n".format( name.ljust(19), r, d, target_mag)) if (len(catalog) > 0): f.write( "{:s} {:s} {:s} 2000.0 ! raoffset={:.2f} decoffset={:.2f} r={:.1f} \n" .format((name + "_S1").ljust(19), S1[0], S1[1], ofR1[0], ofR1[1], catalog["mag"][0])) if (len(catalog) > 1): f.write( "{:s} {:s} {:s} 2000.0 ! raoffset={:.2f} decoffset={:.2f} r={:.1f} \n" .format((name + "_S2").ljust(19), S2[0], S2[1], ofR2[0], ofR2[1], catalog["mag"][1])) f.write('\n')
def img_cutout(img, wcs, coord_1, coord_2, size=60.0, pix=0.168, prefix='img_cutout', pixel_unit=False, img_header=None, out_dir=None, save=True): """(From kungpao) Generate image cutout with updated WCS information. ---------- Parameters: pixel_unit: boolen, optional When True, coord_1, cooord_2 becomes X, Y pixel coordinates. Size will also be treated as in pixels. img: 2d array. wcs: astropy wcs object of the input image. coord_1: ra of the center. coord_2: dec of the center. size: image size, default in arcsec unit. pix: pixel size. img_header: the astropy header object of the input image. In case you can save the infomation in this header to the new header. """ from astropy.nddata import Cutout2D if not pixel_unit: # imgsize in unit of arcsec cutout_size = np.asarray(size) / pix cen_x, cen_y = wcs.wcs_world2pix(coord_1, coord_2, 0) else: cutout_size = np.asarray(size) cen_x, cen_y = coord_1, coord_2 cen_pos = (int(cen_x), int(cen_y)) dx = -1.0 * (cen_x - int(cen_x)) dy = -1.0 * (cen_y - int(cen_y)) # Generate cutout cutout = Cutout2D(img, cen_pos, cutout_size, wcs=wcs) # Update the header cutout_header = cutout.wcs.to_header() if img_header is not None: intersect = [k for k in img_header if k not in cutout_header] for keyword in intersect: cutout_header.set(keyword, img_header[keyword], img_header.comments[keyword]) # Build a HDU hdu = fits.PrimaryHDU(header=cutout_header) hdu.data = cutout.data # Save FITS image if save: fits_file = prefix + '.fits' if out_dir is not None: fits_file = os.path.join(out_dir, fits_file) hdu.writeto(fits_file, overwrite=True) return cutout, [cen_pos, dx, dy], cutout_header
def get_finder(ra, dec, name, rad=0.01, target_mag=np.nan, starlist=None, print_starlist=True, telescope="P200", main_comment="", minmag=15, maxmag=18.5, figdir=None): """ Aim: Generate finder chart Parameters: ra: float or string. eg: ra="18h24m25.36s", 210.437583 dec: float or string, type must be consistent with ra. eg: dec="+44d07m50.0s", 46.215583 name: ZTFname or host name. eg: name="18aaslhxt_h", "ZTF18abclfee" rad: search radius in the unit of degree target_mag: magnitude of the target at time of observation, default shoudl be r band starlist: name of the starlist eg: starlist="/Users/yuhanyao/Desktop/observation/20190428_LRIS/starlist" References: Keck starlist format: https://www2.keck.hawaii.edu/observing/starlist.html First field is the target name in columns 1-16 (tabs and spaces allowed). Maximum length is 15 characters. Next three space-separated tokens (beginning in column 17) are RA in the form HH MM SS.SS (including an arbitrary number of decimal places). Next three space-separated tokens are Dec in the form (-)DD MM SS.S (again, to an arbitrary number of decimal places). Note: if the Dec is between 0 and -1, the DD field MUST be -00). Next token is equinox in the form YYYY.YY (no parentheses; arbitrary number of decimal places), with <=1950 meaning FK4 and 2000 meaning FK5 and APP meaning apparent. """ print('Using search radius of %.1f arcsec.' % (rad * 3600)) name = str(name) #assert len(name) in [12, 11] assert type(ra) == type(dec) if type(ra) == str: c1 = SkyCoord(ra, dec, frame='icrs') ra = c1.ra.degree dec = c1.dec.degree ra = float(ra) dec = float(dec) # prepare to print starlist if telescope == "Keck": name_length = 16 # maximum length of name is 15 commentchar = "#" separator = "" rah_length = 11 elif telescope == "P200": name_length = 20 commentchar = "!" separator = "|" rah_length = 12 #Write to the starlist if the name of the starlist was provided. rah, dech = deg2hour(ra, dec, sep=" ") if (not starlist is None): s_target_mag = "yyao: (r={0:.1f})".format(target_mag) if telescope == "Keck": with open(starlist, "a") as f: f.write("{:s}{:s} {:s} 2000.0 {:s} {:s} {:s} {:s} \n".format( name.ljust(name_length), rah.ljust(rah_length), dech, commentchar, main_comment, separator, s_target_mag)) f.close() elif telescope == "P200": with open(starlist, "a") as f: f.write("{:s}{:s} {:s} 2000.0 {:s} {:s} {:s} {:s} \n".format( name.ljust(name_length), rah.ljust(rah_length), dech, commentchar, main_comment, separator, s_target_mag)) f.close() # Get metadata of all images at this location print("Querying for metadata...") zquery = query.ZTFQuery() zquery.load_metadata(radec=[ra, dec], size=rad) out = zquery.metatable # Do you need to use a reference image? need_ref = len(out) == 0 if need_ref or name[:4] == "ZTFJ": print("Using a reference image") imfile, catfile = choose_ref(zquery, ra, dec) else: print("Using a science image") imfile, catfile = choose_sci(zquery, out, name, ra, dec) # get the cutout inputf = pyfits.open(imfile) im = inputf[0].data inputf.close() head = fits.getheader(imfile) # Get the x and y position of the target, # as per the IPAC catalog wcs = astropy.wcs.WCS(head) world = np.array([[ra, dec]], np.float_) target_pix = wcs.wcs_world2pix(world, 0)[0] xpos = target_pix[0] ypos = target_pix[1] # adjust counts im[np.isnan(im)] = 0 im[im > 30000] = 30000 # extract 600x600 region around the position of the target width = 600 height = 600 xmax = xpos + width / 2 xmin = xpos - width / 2 ymax = ypos + height / 2 ymin = ypos - height / 2 plt.figure(figsize=(8, 6)) plt.set_cmap('gray_r') smoothedimage = gaussian_filter(im, 1.3) # pad the image im_padded = np.pad(smoothedimage, 300, mode='constant', constant_values=0) # If it's a reference image, you have to flip it up/down and left/right if need_ref: croppedimage = np.fliplr( np.flipud(im_padded[int(ymin) + 300:int(ymax) + 300, int(xmin) + 300:int(xmax) + 300])) # If it's a science image, you just flip it up/down else: croppedimage = np.flipud(im_padded[int(ymin) + 300:int(ymax) + 300, int(xmin) + 300:int(xmax) + 300]) plt.imshow( croppedimage, origin='lower', # convention for IPAC images vmin=np.percentile(im.flatten(), 10), vmax=np.percentile(im.flatten(), 99.0)) # Mark target: should just be the center of the image, now # horizontal line plt.plot([300 + 5, 300 + 20], [300, 300], 'g-', lw=2) # vertical line plt.plot([300, 300], [300 + 5, 300 + 20], 'g-', lw=2) # and the offset of the original coordinate system with the new coordinates offset_x = xpos - 300 offset_y = ypos - 300 # Choose offset stars cat = pyfits.open(catfile)[1].data zp = pyfits.open(catfile)[0].header['MAGZP'] sep_pix = np.sqrt( (xpos-cat['xpos'])**2 + \ (ypos-cat['ypos'])**2) # should be separated by at least 10 pixels crit_a = np.logical_and(sep_pix > 10, cat['flags'] == 0) crit_b = np.logical_and(cat['chi'] < 2, cat['snr'] > 10) crit_c = cat['sharp'] < 0.3 crit_ab = np.logical_and(crit_a, crit_b) crit = np.logical_and(crit_ab, crit_c) # should be bright mag_crit = np.logical_and(cat['mag'] + zp >= minmag, cat['mag'] + zp <= maxmag) choose_ind = np.where(np.logical_and(crit, mag_crit)) # mark the closest three stars nref = 3 order = np.argsort(sep_pix[choose_ind]) cols = ['orange', 'purple', 'red'] for ii in np.arange(nref): ref_xpos_original = cat['xpos'][choose_ind][order][ii] - offset_x ref_ypos_original = cat['ypos'][choose_ind][order][ii] - offset_y # transform to flipped plot if need_ref: ref_xpos = 600 - ref_xpos_original ref_ypos = 600 - ref_ypos_original else: ref_xpos = ref_xpos_original ref_ypos = 600 - ref_ypos_original plt.plot([ref_xpos + 5, ref_xpos + 20], [ref_ypos, ref_ypos], c=cols[ii], ls='-', lw=2) plt.plot([ref_xpos, ref_xpos], [ref_ypos + 5, ref_ypos + 20], c=cols[ii], ls='-', lw=2) refra = cat['ra'][choose_ind][order][ii] refdec = cat['dec'][choose_ind][order][ii] if telescope == 'Keck': refrah, refdech = deg2hour(refra, refdec, sep=" ") elif telescope == 'P200': refrah, refdech = deg2hour(refra, refdec, sep=":") else: print("I don't recognize this telescope") refmag = cat['mag'][choose_ind][order][ii] + zp dra, ddec = get_offset(refra, refdec, ra, dec) offsetnum = 0.2 plt.text(1.02, 0.60 - offsetnum * ii, 'Ref S%s, mag %s' % ((ii + 1), np.round(refmag, 1)), transform=plt.axes().transAxes, fontweight='bold', color=cols[ii]) plt.text(1.02, 0.55 - offsetnum * ii, '%s %s' % (refrah, refdech), color=cols[ii], transform=plt.axes().transAxes) plt.text(1.02, 0.50 - offsetnum * ii, str(np.round(ddec, 2)) + "'' N, " + str(np.round(dra, 2)) + "'' E", color=cols[ii], transform=plt.axes().transAxes) # Print starlist for telescope if telescope == 'Keck': # Target name is columns 1-16 # RA must begin in 17, separated by spaces print( "{:s}{:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} {:s} r={:.1f} " .format((name + "_S%s" % (ii + 1)).ljust(name_length), refrah.ljust(rah_length), refdech, separator, dra, ddec, commentchar, refmag)) elif telescope == 'P200': print( "{:s}{:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} r={:.1f} \n" .format((name + "_S%s" % (ii + 1)).ljust(name_length), refrah.ljust(rah_length), refdech, commentchar, dra, ddec, refmag)) # and save to file if starlist name is provided if (not starlist is None): if telescope == "Keck": with open(starlist, "a") as f: f.write( "{:s}{:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} {:s} r={:.1f} \n" .format((name + "_S%s" % (ii + 1)).ljust(name_length), refrah.ljust(rah_length), refdech, commentchar, dra, ddec, separator, refmag)) f.close() elif telescope == "P200": with open(starlist, "a") as f: f.write( "{:s}{:s} {:s} 2000.0 {:s} raoffset={:.2f} decoffset={:.2f} r={:.1f} \n" .format((name + "_S%s" % (ii + 1)).ljust(name_length), refrah.ljust(rah_length), refdech, commentchar, dra, ddec, refmag)) f.close() # Plot compass plt.plot([width - 10, height - 40], [10, 10], 'k-', lw=2) plt.plot([width - 10, height - 10], [10, 40], 'k-', lw=2) plt.annotate("N", xy=(width - 20, 40), xycoords='data', xytext=(-4, 5), textcoords='offset points') plt.annotate("E", xy=(height - 40, 20), xycoords='data', xytext=(-12, -5), textcoords='offset points') # Get rid of axis labels plt.gca().get_xaxis().set_visible(False) plt.gca().get_yaxis().set_visible(False) # Set size of window (leaving space to right for ref star coords) plt.subplots_adjust(right=0.65, left=0.05, top=0.99, bottom=0.05) # List name, coords, mag of the target plt.text(1.02, 0.85, name, transform=plt.axes().transAxes, fontweight='bold') # Can't print mag, because we don't know how bright the target is #plt.text(1.02, 0.80, "%s"%mag, transform=plt.axes().transAxes, fontweight='bold') plt.text(1.02, 0.80, "%.5f %.5f" % (ra, dec), transform=plt.axes().transAxes) rah, dech = deg2hour(ra, dec) plt.text(1.02, 0.75, rah + " " + dech, transform=plt.axes().transAxes) if figdir == None: plt.savefig("finder_chart_%s.png" % name) else: plt.savefig(figdir + "finder_chart_%s.png" % name) plt.close()
def make_finder(image='A2744_DSS_r.fits', ra=3.5313884, dec=-30.389218, pa=53.8-90, target='A2744 (Ks)', image_label='DSS-r', progID = '092.A-0472(A)', PI = 'G. Brammer', vscale=None): import matplotlib.pyplot as plt import astropy.wcs import finder # plt.gray() im = pyfits.open(image)[0].data wcs = astropy.wcs.WCS(pyfits.getheader(image)) px, py = finder.make_regions(ra=ra, dec=dec, pa=pa) fig = unicorn.plotting.plot_init(xs=6, aspect=1.1, left=0.01, right=0.01, top=0.01, bottom=0.01) ax = fig.add_axes((0.01, 0.01, 0.98, 0.88)) #(111) if vscale is None: vscale = np.percentile(im, [0.1,99.8]) print 'Vscale: %.2f, %.2f' %(vscale[0], vscale[1]) ai = ax.imshow(0-im, vmin=-vscale[1], vmax=-vscale[0], aspect='auto', interpolation='nearest', label=image_label) colors = ['magenta', 'black','black','black'] for i in range(4): bx, by = wcs.wcs_world2pix(px[i], py[i], 0) ax.plot(bx, by, color=colors[i], label='HAWKI, Chip 1'*(i==0)) ### 10x10 box bx, by = wcs.wcs_world2pix(px[-1], py[-1], 0) ax.plot(bx, by, color='black', linestyle='--', label=r"$10\times10$ arcmin") ax.set_xlim(0, im.shape[1]) ax.set_xticks([0, im.shape[1]]) ax.set_ylim(0, im.shape[0]) ax.set_yticks([0, im.shape[0]]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.text(0.02, 0.98, 'Image: %s' %(image_label), ha='left', va='top', transform=ax.transAxes, size=14) axt = fig.add_axes((0.01, 0.89, 0.98, 0.1)) axt.text(0.02, 0.9, '%s, PI: %s' %(progID, PI), ha='left', va='top', size=17, transform=axt.transAxes) axt.text(0.02, 0.1, 'Target: %s' %(target), ha='left', va='bottom', size=17, transform=axt.transAxes) axt.text(0.98, 0.1, 'PA = %.1f' %(pa), ha='right', va='bottom', size=12, transform=axt.transAxes) axt.set_xticklabels([]) axt.set_yticklabels([]) axt.set_xlim(0,1); axt.set_xticks([]) axt.set_ylim(0,1); axt.set_yticks([]) ax.legend(loc='lower right') ax.arrow(0.15,0.05, -0.1, 0, transform=ax.transAxes, color='black', head_length=0.01, head_width=0.01) ax.arrow(0.15,0.05, 0, 0.1, transform=ax.transAxes, color='black', head_length=0.01, head_width=0.01) ax.text(0.05, 0.05+0.02, 'E', ha='center', va='bottom', transform=ax.transAxes) ax.text(0.15-0.02, 0.15, 'N', ha='right', va='center', transform=ax.transAxes) return fig, ax