def read(self, filename, hdu=None): self.filename = filename self.name = self.name or os.path.basename(filename) # read FITS file if not hdu: dprint(3, "opening", filename) hdu = pyfits.open(filename)[0] hdu.verify('silentfix') hdr = self.fits_header = hdu.header dprint(3, "reading data") data = hdu.data # NB: all-data operations (such as getting global min/max or computing of histograms) are much faster # (almost x2) when data is iterated # over in the proper order. After a transpose(), data is in fortran order. Tell this to setData(). data = numpy.transpose(data) # .copy() dprint(3, "setting data") self.setData(data, fortran_order=True) dprint(3, "reading header") ndim = hdr['NAXIS'] if ndim < 2: raise ValueError, "Cannot load a one-dimensional FITS file" # setup projection # (strip out history from header, as big histories really slow down FITSWCS) hdr1 = pyfits.Header( filter(lambda x: not str(x).startswith('HISTORY'), hdr.cards)) proj = Projection.FITSWCS(hdr1) nx = ny = None # find X and Y axes for iaxis in range(ndim): axs = str(iaxis + 1) npix = hdr['NAXIS' + axs] name = hdr.get('CTYPE' + axs, axs).strip().upper() # have we found the coordinate axes? if FITSHeaders.isAxisTypeX(name): nx = npix iaxis_ra = iaxis elif FITSHeaders.isAxisTypeY(name): ny = npix iaxis_dec = iaxis # check that we have them if nx is None or ny is None: iaxis_ra, iaxis_dec = 0, 1 nx, ny = hdr.get('NAXIS1'), hdr.get('NAXIS2') for iaxis in range(ndim): axs = str(iaxis + 1) # get axis description npix = hdr['NAXIS' + axs] crval = hdr.get('CRVAL' + axs, 0) cdelt = hdr.get('CDELT' + axs, 1) crpix = hdr.get('CRPIX' + axs, 1) - 1 name = hdr.get('CTYPE' + axs, axs).strip().upper() unit = hdr.get('CUNIT' + axs) # if this is not an X/Y axis, add it to the slicers if iaxis not in (iaxis_ra, iaxis_dec): # values becomes a list of axis values values = list(crval + (numpy.arange(npix) - crpix) * cdelt) unit = unit and unit.lower().capitalize() # FITS knows of two enumerable axes: STOKES and COMPLEX. For these two, replace values with proper names if name == "STOKES": labels = [(self.StokesNames[int(i)] if i > 0 and i < len(self.StokesNames) else "%d" % i) for i in values] elif name == "COMPLEX": labels = [(self.ComplexNames[int(i)] if i > 0 and i < len(self.ComplexNames) else "%d" % i) for i in values] else: name = name.split("-")[0] # if values are a simple sequence startying at 0 or 1, make simple labels if cdelt == 1 and values[0] in (0., 1.): labels = ["%d%s" % (val, unit) for val in values] # else set labels to None: setExtraAxis() will figure it out else: labels = None self.setExtraAxis(iaxis, name or ("axis " + axs), labels, values, unit) # check for beam parameters psf = [hdr.get(x, None) for x in 'BMAJ', 'BMIN', 'BPA'] if all([x is not None for x in psf]): self.setPsfSize(*[p / 180 * math.pi for p in psf]) self.setSkyAxis(0, iaxis_ra, nx, proj.ra0, -proj.xscale, proj.xpix0) self.setSkyAxis(1, iaxis_dec, ny, proj.dec0, proj.yscale, proj.ypix0) self.setDefaultProjection(proj) dprint(3, "setting initial slice") self._setupSlice()
def getImageCube (fitshdu,filename="",extra_axes=None): """Converts a FITS HDU (consisting of a header and data) into a 4+-dim numpy array where the first two axes are x and y, the third is Stokes (possibly of length 1, if missing in the original image), and the rest are either as found in the FITS header (if extra_axes=None), or in the order specified by CTYPE in extra_axes (if present, else a dummy axis of size 1 is inserted), with axes not present in extra_axes removed by taking the 0-th plane along each. Returns tuple of array,stokes_list,extra_axes_ctype_list,removed_axes_ctype_list e.g. array,("I","Q"),("FREQ--FOO","TIME--BAR") """ hdr = fitshdu.header; data = fitshdu.data; # recognized axes ix = iy = istokes = None; naxis = len(data.shape); # other axes which will be returned other_axes = []; other_axes_ctype = []; remove_axes = []; remove_axes_ctype = []; # match axis ctype # this makes FREQ equivalent to FELO* def match_ctype (ctype,ctype_list): for i,ct in enumerate(ctype_list): if ct == ctype or ( ct == "FREQ" and ctype.startswith("FELO") ) or ( ctype == "FREQ" and ct.startswith("FELO") ): return i; return None; # identify X, Y and stokes axes for n in range(naxis): iax = naxis-1-n; axs = str(n+1); ctype = hdr.get('CTYPE'+axs).strip().upper(); if ix is None and FITSHeaders.isAxisTypeX(ctype): ix = iax; # in numpy order, axes are reversed elif iy is None and FITSHeaders.isAxisTypeY(ctype): iy = iax; elif ctype == 'STOKES': if istokes is not None: raise ValueError,"duplicate STOKES axis in FITS file %s"%filename; istokes = iax; crval = hdr.get('CRVAL'+axs,0); cdelt = hdr.get('CDELT'+axs,1); crpix = hdr.get('CRPIX'+axs,1)-1; values = map(int,list(crval + (numpy.arange(data.shape[iax]) - crpix)*cdelt)); stokes_names = [ (FITSHeaders.StokesNames[i] if i>0 and i<len(FITSHeaders.StokesNames) else "%d"%i) for i in values ]; else: other_axes.append(iax); other_axes_ctype.append(ctype); # not found? if ix is None or iy is None: raise ValueError,"FITS file %s does not appear to contain an X and/or Y axis"%filename; # form up shape of resulting image, and order of axes for transpose shape = [data.shape[ix],data.shape[iy]]; axes = [ix,iy]; # add stokes axis if istokes is None: shape.append(1); stokes_labels = ("I",); else: shape.append(data.shape[istokes]); axes.append(istokes); if extra_axes: # if a fixed order for the extra axes is specified, add the ones we found for ctype in extra_axes: i = match_ctype(ctype,other_axes_ctype); if i is not None: iax = other_axes[i]; axes.append(iax); shape.append(data.shape[iax]); else: shape.append(1); # add the ones that were not found into the remove list for iaxis,ctype in zip(other_axes,other_axes_ctype): if match_ctype(ctype,extra_axes) is None: axes.append(iaxis); remove_axes.append(iaxis); remove_axes_ctype.append(ctype); # return all extra axes found in header else: shape += [ data.shape[i] for i in other_axes ]; axes += other_axes; extra_axes = other_axes_ctype; # tranpose data = data.transpose(axes); # trim off axes which are to be removed, if we have any if remove_axes: data = data[[Ellipsis]+[0]*len(remove_axes)]; # reshape and return return data.reshape(shape),stokes_names,extra_axes,remove_axes_ctype;
def getImageCube(fitshdu, filename="", extra_axes=None): """Converts a FITS HDU (consisting of a header and data) into a 4+-dim numpy array where the first two axes are x and y, the third is Stokes (possibly of length 1, if missing in the original image), and the rest are either as found in the FITS header (if extra_axes=None), or in the order specified by CTYPE in extra_axes (if present, else a dummy axis of size 1 is inserted), with axes not present in extra_axes removed by taking the 0-th plane along each. Returns tuple of array,stokes_list,extra_axes_ctype_list,removed_axes_ctype_list e.g. array,("I","Q"),("FREQ--FOO","TIME--BAR") """ hdr = fitshdu.header data = fitshdu.data # recognized axes ix = iy = istokes = None naxis = len(data.shape) # other axes which will be returned other_axes = [] other_axes_ctype = [] remove_axes = [] remove_axes_ctype = [] # match axis ctype # this makes FREQ equivalent to FELO* def match_ctype(ctype, ctype_list): for i, ct in enumerate(ctype_list): if ct == ctype or (ct == "FREQ" and ctype.startswith("FELO")) or ( ctype == "FREQ" and ct.startswith("FELO")): return i return None # identify X, Y and stokes axes for n in range(naxis): iax = naxis - 1 - n axs = str(n + 1) ctype = hdr.get('CTYPE' + axs).strip().upper() if ix is None and FITSHeaders.isAxisTypeX(ctype): ix = iax # in numpy order, axes are reversed elif iy is None and FITSHeaders.isAxisTypeY(ctype): iy = iax elif ctype == 'STOKES': if istokes is not None: raise ValueError, "duplicate STOKES axis in FITS file %s" % filename istokes = iax crval = hdr.get('CRVAL' + axs, 0) cdelt = hdr.get('CDELT' + axs, 1) crpix = hdr.get('CRPIX' + axs, 1) - 1 values = map( int, list(crval + (numpy.arange(data.shape[iax]) - crpix) * cdelt)) stokes_names = [ (FITSHeaders.StokesNames[i] if i > 0 and i < len(FITSHeaders.StokesNames) else "%d" % i) for i in values ] else: other_axes.append(iax) other_axes_ctype.append(ctype) # not found? if ix is None or iy is None: raise ValueError, "FITS file %s does not appear to contain an X and/or Y axis" % filename # form up shape of resulting image, and order of axes for transpose shape = [data.shape[ix], data.shape[iy]] axes = [ix, iy] # add stokes axis if istokes is None: shape.append(1) stokes_names = ("I", ) else: shape.append(data.shape[istokes]) axes.append(istokes) if extra_axes: # if a fixed order for the extra axes is specified, add the ones we found for ctype in extra_axes: i = match_ctype(ctype, other_axes_ctype) if i is not None: iax = other_axes[i] axes.append(iax) shape.append(data.shape[iax]) else: shape.append(1) # add the ones that were not found into the remove list for iaxis, ctype in zip(other_axes, other_axes_ctype): if match_ctype(ctype, extra_axes) is None: axes.append(iaxis) remove_axes.append(iaxis) remove_axes_ctype.append(ctype) # return all extra axes found in header else: shape += [data.shape[i] for i in other_axes] axes += other_axes extra_axes = other_axes_ctype # tranpose data = data.transpose(axes) # trim off axes which are to be removed, if we have any if remove_axes: data = data[[Ellipsis] + [0] * len(remove_axes)] # reshape and return return data.reshape(shape), stokes_names, extra_axes, remove_axes_ctype
def read (self,filename,hdu=None): self.filename = filename; self.name = self.name or os.path.basename(filename); # read FITS file if not hdu: dprint(3,"opening",filename); hdu = pyfits.open(filename)[0]; hdu.verify('silentfix'); hdr = self.fits_header = hdu.header; dprint(3,"reading data"); data = hdu.data; # NB: all-data operations (such as getting global min/max or computing of histograms) are much faster # (almost x2) when data is iterated # over in the proper order. After a transpose(), data is in fortran order. Tell this to setData(). data = numpy.transpose(data); # .copy() dprint(3,"setting data"); self.setData(data,fortran_order=True); dprint(3,"reading header"); ndim = hdr['NAXIS']; if ndim < 2: raise ValueError,"Cannot load a one-dimensional FITS file"; # setup projection # (strip out history from header, as big histories really slow down FITSWCS) hdr1 = pyfits.Header(filter(lambda x:not str(x).startswith('HISTORY'),hdr.cards)); proj = Projection.FITSWCS(hdr1); nx = ny = None; # find X and Y axes for iaxis in range(ndim): axs = str(iaxis+1); npix = hdr['NAXIS'+axs]; name = hdr.get('CTYPE'+axs,axs).strip().upper(); # have we found the coordinate axes? if FITSHeaders.isAxisTypeX(name): nx = npix; iaxis_ra = iaxis; elif FITSHeaders.isAxisTypeY(name): ny = npix; iaxis_dec = iaxis; # check that we have them if nx is None or ny is None: iaxis_ra,iaxis_dec = 0,1; nx,ny = hdr.get('NAXIS1'),hdr.get('NAXIS2'); for iaxis in range(ndim): axs = str(iaxis+1); # get axis description npix = hdr['NAXIS'+axs]; crval = hdr.get('CRVAL'+axs,0 ); cdelt = hdr.get('CDELT'+axs,1) ; crpix = hdr.get('CRPIX'+axs,1) -1; name = hdr.get('CTYPE'+axs,axs).strip().upper(); unit = hdr.get('CUNIT'+axs); # if this is not an X/Y axis, add it to the slicers if iaxis not in (iaxis_ra,iaxis_dec): # values becomes a list of axis values values = list(crval + (numpy.arange(npix) - crpix)*cdelt); unit = unit and unit.lower().capitalize(); # FITS knows of two enumerable axes: STOKES and COMPLEX. For these two, replace values with proper names if name == "STOKES": labels = [ (self.StokesNames[int(i)] if i>0 and i<len(self.StokesNames) else "%d"%i) for i in values ]; elif name == "COMPLEX": labels = [ (self.ComplexNames[int(i)] if i>0 and i<len(self.ComplexNames) else "%d"%i) for i in values ]; else: name = name.split("-")[0]; # if values are a simple sequence startying at 0 or 1, make simple labels if cdelt == 1 and values[0] in (0.,1.): labels = [ "%d%s"%(val,unit) for val in values ]; # else set labels to None: setExtraAxis() will figure it out else: labels = None; self.setExtraAxis(iaxis,name or ("axis "+axs),labels,values,unit); # check for beam parameters psf = [ hdr.get(x,None) for x in 'BMAJ','BMIN','BPA' ]; if all([x is not None for x in psf]): self.setPsfSize(*[ p/180*math.pi for p in psf ]); self.setSkyAxis(0,iaxis_ra,nx,proj.ra0,-proj.xscale,proj.xpix0); self.setSkyAxis(1,iaxis_dec,ny,proj.dec0,proj.yscale,proj.ypix0); self.setDefaultProjection(proj); dprint(3,"setting initial slice"); self._setupSlice();