agpy 0.1 documentation

Source code for agpy.cutout

"""
======
Cutout
======

Generate a cutout image from a .fits file
"""
import pyfits
import numpy
import pywcs
import coords
try:
    import montage
    import os
    CanUseMontage=True
except ImportError:
    CanUseMontage=False

[docs]class DimensionError(ValueError): pass
[docs]def cutout(filename, xc, yc, xw=25, yw=25, units='pixels', outfile=None, clobber=True, useMontage=False, coordsys='celestial', verbose=False): """ 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) units - specify units to use: either pixels or wcs outfile - optional output file """ 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_sky2pix(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