def baseline(hdu, chan, windows, order=0, subtract=True, returnrms=True, kms=True): #this function needs to be passed a FITS HDU #with data in the (V,X,Y) format header = None if isinstance(hdu, pyfits.hdu.image.PrimaryHDU): # get data and header from the hdu header = hdu.header data = hdu.data elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, pyfits.header.Header): raise SculptArgumentError( 'header', "Since you passed in data that is a numpy array, set header to a pyfits header type" ) data = hdu shape = data.shape #windows over which to do the test for sigma values #basically excluse major lines you observe lenv, lenx, leny = shape #defaultswindow = ((100,200),(650,750)) sigma = numpy.zeros((lenx, leny)) x = numpy.arange(lenv) c_loop = 0 # this commented section is the makermsimage way of selecting them # if someone wants to make a change regarding one being better, do it # velax = getaxes(header, 1) # indices = numpy.zeros(velax.shape, dtype=bool) # for v1, v2 in window: # if chan: # indices[v1:v2] = True # else: # ind = numpy.logical_and(velax>= v1, velax<= v2) # indices = numpy.logical_or(indices, ind) # indices = numpy.logical_not(indices) # for indices to include in std calc for win in windows: if (len(win) != 2): print "Each element in the window list must be a 2-tuple" c1, c2 = win c1, c2 = sorted((c1, c2)) ind = numpy.logical_and(x >= c1, x <= c2) if (c_loop == 0): final_ind = numpy.logical_or(ind, ind) else: final_ind = numpy.logical_or(final_ind, ind) x_windows = x[final_ind] for ix in range(lenx): for iy in range(leny): spectra = data[:, ix, iy] spec_windows = spectra[final_ind] p = numpy.polyfit(x_windows, spec_windows, order) spec_windows -= numpy.polyval(p, len(x_windows)) sigma[ix, iy] = spec_windows.std() if (subtract): data[:, ix, iy] -= numpy.polyval(p, lenv) # this is the original input - with data reduced as needed hdu_orig = pyfits.hdu.image.PrimaryHDU(header=header, data=data) if returnrms: #the following grabs relevant information from the original header #and reproduces it in the RMSMap header shifted to account for #the different shape of the data crpix1 = sxpar(header, "CRPIX1") crval1 = sxpar(header, "CRVAL1") cdelt1 = sxpar(header, "CDELT1") if kms: #convert velocity to km/s crval1 = crval1 / 1000. cdelt1 = cdelt1 / 1000. ctype1 = sxpar(header, "CTYPE1") crpix2 = sxpar(header, "CRPIX2") crval2 = sxpar(header, "CRVAL2") cdelt2 = sxpar(header, "CDELT2") ctype2 = sxpar(header, "CTYPE2") crpix3 = sxpar(header, "CRPIX3") crval3 = sxpar(header, "CRVAL3") cdelt3 = sxpar(header, "CDELT3") ctype3 = sxpar(header, "CTYPE3") nv = sxpar(header, "NAXIS1") nx = sxpar(header, "NAXIS2") ny = sxpar(header, "NAXIS3") blank = sxpar(header, "BLANK") hnew = header.copy() sxaddpar(hnew, "CRVAL1", crval2, comment="DEGREES") sxaddpar(hnew, "CRPIX1", crpix2) sxaddpar(hnew, "CDELT1", cdelt2, comment="DEGREES") sxaddpar(hnew, "CTYPE1", ctype2) sxaddpar(hnew, "CRVAL2", crval3, comment="DEGREES") sxaddpar(hnew, "CRPIX2", crpix3) sxaddpar(hnew, "CDELT2", cdelt3, comment="DEGREES") sxaddpar(hnew, "CTYPE2", ctype3) sxaddpar(hnew, "NAXIS", 2) sxaddpar(hnew, "NAXIS1", nx) sxaddpar(hnew, "NAXIS2", ny) sxaddpar(hnew, "NAXIS3", 1) sxaddpar(hnew, "NAXIS4", 1) if chan: vorc = 'CHANNEL' else: vorc = 'VELOCITY' sxaddhist(hnew, "WINDOW : %s; Window %s LIMITS" % (repr(windows), vorc)) #sxaddpar(hnew, "BUNIT", units, "Units") sxdelpar(hnew, "CRVAL3") sxdelpar(hnew, "CRPIX3") sxdelpar(hnew, "CDELT3") sxdelpar(hnew, "CTYPE3") sxdelpar(hnew, "NAXIS3") sxdelpar(hnew, "NAXIS4") hdu_rms = pyfits.hdu.image.PrimaryHDU(data=sigma, header=hnew) return (hdu_orig, hdu_rms) else: return hdu_orig
def momentcube(hdu, v1, v2, header=None, chan=False, dontblank=False, kms=True, moment=0, returnrms=False, window=None): """ Create 2d moment image from cube. The input cube is expected to be in the VLM format @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. This cube is expected to be in vlm format. If numpy format data cube is passed, then the header parameter should also be passed in. @type hdu: pyfits HDU or numpy array @param header: pyfits style header object that corresponds to the hdu data variable. This header parameter is only considered if the hdu parameter is a numpy array type rather than a pyfits HDU type @type header: pyfits header object @param v1: lower velocity to be used (If chan is set to True, this should be an integer). If chan is False, this is expected to be velocity expressed in kms (if the input parameter kms is True). If chan is False, and kms is False, v1 is treated with the same units as the FITS header describes. @param v2: upper velocity to be used. Same explanation as v1 @param chan: If True, v1 and v2 are treated as channels. If False, they are treated as velocity @type chan: Boolean @param dontblank: By default, momentcube will use the BLANK fits header value and automatically zero blanked values in order to compute moments. If dontblank keyword is set, then such blanking is not performed. @type dontblank: Boolean @param kms: If True velocity units is in kms. @type kms: Boolean @param moment: which moment to extract. default is moment=0 - moment=0 - integrated intensity - moment=1 - centroid velocity - moment=2 - width @type moment: int @param returnrms: If True, return image of the noise in the moment map @type returnrms: Boolean @param window: list of tuples (pairs) of channels/velocity to exclude from polynomial calculation in determining rms. If chan is set to True, these should be integers. If chan is False, this is expected to be velocity expressed in kms (if the input parameter kms is True). If chan is False, and kms is False, window is treated with the same units as the FITS header describes. @return: A HDU instance with 2d output map in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. If returnrms is True, returns the momentmap and rms image as a tuple. """ if moment not in range(3): raise SculptArgumentError('moment', "moment can only be one of 0,1,2") if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError( 'header', "Since you passed in data that is a numpy array, set header to a pyfits header type" ) data = hdu else: raise SculptArgumentError( 'hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") if returnrms and window is None: raise SculptArgumentError( 'rms', 'if returnrms is True, you need to specify a window to do the rms calculation in' ) if returnrms and moment != 0: raise SculptArgumentError('rms', 'For now, only moment=0 return rms image') # calculate the x-axis (velocity) crpix1 = sxpar(header, "CRPIX1") crval1 = sxpar(header, "CRVAL1") cdelt1 = sxpar(header, "CDELT1") if kms: #convert velocity to km/s crval1 = crval1 / 1000. cdelt1 = cdelt1 / 1000. ctype1 = sxpar(header, "CTYPE1") crpix2 = sxpar(header, "CRPIX2") crval2 = sxpar(header, "CRVAL2") cdelt2 = sxpar(header, "CDELT2") ctype2 = sxpar(header, "CTYPE2") crpix3 = sxpar(header, "CRPIX3") crval3 = sxpar(header, "CRVAL3") cdelt3 = sxpar(header, "CDELT3") ctype3 = sxpar(header, "CTYPE3") nv = sxpar(header, "NAXIS1") nx = sxpar(header, "NAXIS2") ny = sxpar(header, "NAXIS3") blank = sxpar(header, "BLANK") #cube = data.copy() if not dontblank and blank is not None: ind = numpy.where(data == blank) data[ind] = 0.0 vind = numpy.zeros(nv, dtype=bool) if not chan: #get velocity axis velax = getaxes(header, 1) if v2 < v1: v1, v2 = v2, v1 if chan: vind[v1:v2 + 1] = True else: vind = numpy.logical_and(velax >= v1, velax <= v2) N = len(numpy.where(vind)[0]) print "The number of spectral channels used, N: %d" % N T = data[:, :, vind].sum(axis=2) #T is integ intensity image now if moment >= 1: C = (data[:, :, vind] * velax[vind]).sum(axis=2) C = C / T #centroid velocity definition if moment == 2: W = (data[:, :, vind] * velax[vind]**2.).sum(axis=2) W = W / T - C**2. hnew = header.copy() sxaddpar(hnew, "CRVAL1", crval2, comment="DEGREES") sxaddpar(hnew, "CRPIX1", crpix2) sxaddpar(hnew, "CDELT1", cdelt2, comment="DEGREES") sxaddpar(hnew, "CTYPE1", ctype2) sxaddpar(hnew, "CRVAL2", crval3, comment="DEGREES") sxaddpar(hnew, "CRPIX2", crpix3) sxaddpar(hnew, "CDELT2", cdelt3, comment="DEGREES") sxaddpar(hnew, "CTYPE2", ctype3) sxaddpar(hnew, "NAXIS", 2) sxaddpar(hnew, "NAXIS1", nx) sxaddpar(hnew, "NAXIS2", ny) sxaddpar(hnew, "NAXIS3", 1) sxaddpar(hnew, "NAXIS4", 1) if chan: vorc = 'CHANNEL' else: vorc = 'VELOCITY' sxaddpar(hnew, "VMIN", v1, "LOWER %s LIMIT" % vorc) sxaddpar(hnew, "VMAX", v2, "UPPER %s LIMIT" % vorc) sxaddpar(hnew, "MOMENT", moment, comment="Order of Moment") if moment == 0: units = "K.km/s" else: units = "km/s" sxaddpar(hnew, "BUNIT", units, "Units") for axis in xrange(3, 5): for attr in ('CRVAL', 'CRPIX', 'CDELT', 'CROTA', 'CTYPE', 'NAXIS'): sxdelpar(hnew, '%s%1d' % (attr, axis)) if moment == 0: dt = T * abs(cdelt1) elif moment == 1: dt = C else: dt = W hdu = pyfits.PrimaryHDU(dt, header=hnew) if moment == 0 and returnrms: specrms = mkrmsimage(data, window=window, header=header) rms_data = specrms.data * abs(cdelt1) * math.sqrt(N) hrms = hnew.copy() sxaddhist(hrms, "WINDOW : %s; Window %s LIMITS" % (repr(window), vorc)) rms = pyfits.PrimaryHDU(rms_data, header=hrms) return hdu, rms return hdu
def baseline(hdu, chan, windows, order = 0, subtract = True, returnrms = True, kms = True): #this function needs to be passed a FITS HDU #with data in the (V,X,Y) format header = None if isinstance(hdu, pyfits.hdu.image.PrimaryHDU): # get data and header from the hdu header = hdu.header data = hdu.data elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, pyfits.header.Header): raise SculptArgumentError('header', "Since you passed in data that is a numpy array, set header to a pyfits header type") data = hdu shape = data.shape #windows over which to do the test for sigma values #basically excluse major lines you observe lenv, lenx, leny = shape #defaultswindow = ((100,200),(650,750)) sigma = numpy.zeros((lenx, leny)) x = numpy.arange(lenv) c_loop = 0 # this commented section is the makermsimage way of selecting them # if someone wants to make a change regarding one being better, do it # velax = getaxes(header, 1) # indices = numpy.zeros(velax.shape, dtype=bool) # for v1, v2 in window: # if chan: # indices[v1:v2] = True # else: # ind = numpy.logical_and(velax>= v1, velax<= v2) # indices = numpy.logical_or(indices, ind) # indices = numpy.logical_not(indices) # for indices to include in std calc for win in windows: if (len(win) != 2): print "Each element in the window list must be a 2-tuple" c1, c2 = win c1, c2 = sorted((c1, c2)) ind = numpy.logical_and(x>=c1, x<=c2) if (c_loop == 0): final_ind = numpy.logical_or(ind,ind) else: final_ind = numpy.logical_or(final_ind,ind) x_windows = x[final_ind] for ix in range(lenx): for iy in range(leny): spectra = data[:,ix,iy] spec_windows = spectra[final_ind] p = numpy.polyfit(x_windows,spec_windows,order) spec_windows -= numpy.polyval(p,len(x_windows)) sigma[ix, iy] = spec_windows.std() if (subtract): data[:,ix,iy] -= numpy.polyval(p,lenv) # this is the original input - with data reduced as needed hdu_orig = pyfits.hdu.image.PrimaryHDU(header = header, data = data) if returnrms: #the following grabs relevant information from the original header #and reproduces it in the RMSMap header shifted to account for #the different shape of the data crpix1 = sxpar(header,"CRPIX1") crval1 = sxpar(header,"CRVAL1") cdelt1 = sxpar(header,"CDELT1") if kms: #convert velocity to km/s crval1 = crval1/1000. cdelt1 = cdelt1/1000. ctype1 = sxpar(header,"CTYPE1") crpix2 = sxpar(header,"CRPIX2") crval2 = sxpar(header,"CRVAL2") cdelt2 = sxpar(header,"CDELT2") ctype2 = sxpar(header,"CTYPE2") crpix3 = sxpar(header,"CRPIX3") crval3 = sxpar(header,"CRVAL3") cdelt3 = sxpar(header,"CDELT3") ctype3 = sxpar(header,"CTYPE3") nv = sxpar(header,"NAXIS1") nx = sxpar(header,"NAXIS2") ny = sxpar(header,"NAXIS3") blank = sxpar(header,"BLANK") hnew = header.copy() sxaddpar(hnew, "CRVAL1", crval2, comment="DEGREES") sxaddpar(hnew, "CRPIX1", crpix2) sxaddpar(hnew, "CDELT1", cdelt2, comment="DEGREES") sxaddpar(hnew, "CTYPE1", ctype2) sxaddpar(hnew, "CRVAL2", crval3, comment="DEGREES") sxaddpar(hnew, "CRPIX2", crpix3) sxaddpar(hnew, "CDELT2", cdelt3, comment="DEGREES") sxaddpar(hnew, "CTYPE2", ctype3) sxaddpar(hnew, "NAXIS", 2) sxaddpar(hnew, "NAXIS1", nx) sxaddpar(hnew, "NAXIS2", ny) sxaddpar(hnew, "NAXIS3", 1) sxaddpar(hnew, "NAXIS4", 1) if chan: vorc = 'CHANNEL' else: vorc = 'VELOCITY' sxaddhist(hnew, "WINDOW : %s; Window %s LIMITS" % (repr(windows), vorc)) #sxaddpar(hnew, "BUNIT", units, "Units") sxdelpar(hnew, "CRVAL3") sxdelpar(hnew, "CRPIX3") sxdelpar(hnew, "CDELT3") sxdelpar(hnew, "CTYPE3") sxdelpar(hnew, "NAXIS3") sxdelpar(hnew, "NAXIS4") hdu_rms = pyfits.hdu.image.PrimaryHDU(data=sigma, header=hnew) return (hdu_orig, hdu_rms) else: return hdu_orig
def mkrmsimage(hdu, window, header=None, chan=False, dontblank=False, kms=True, moment=0): """ Create rms image from spectral cube. The input cube is expected to be in the VLM format @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. This cube is expected to be in vlm format. If numpy format data cube is passed, then the header parameter should also be passed in. @type hdu: pyfits HDU or numpy array @param header: pyfits style header object that corresponds to the hdu data variable. This header parameter is only considered if the hdu parameter is a numpy array type rather than a pyfits HDU type @type header: pyfits header object @param window: list of tuples (pairs) of channels/velocity to exclude from polynomial calculation in determining rms. If chan is set to True, these should be integers. If chan is False, this is expected to be velocity expressed in kms (if the input parameter kms is True). If chan is False, and kms is False, v1 is treated with the same units as the FITS header describes. @param chan: If True, window variables are treated as channels. If False, they are treated as velocity @type chan: Boolean @param dontblank: By default, mkrmsimage will use the BLANK fits header value and automatically zero blanked values in order to compute rms. If dontblank keyword is set, then such blanking is not performed. @type dontblank: Boolean @param kms: If True velocity units is in kms. @type kms: Boolean @return: A HDU instance with 2d output map in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError( 'header', "Since you passed in data that is a numpy array, set header to a pyfits header type" ) data = hdu else: raise SculptArgumentError( 'hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") #check for list or tuple type of window if type(window) not in (types.ListType, types.TupleType): raise SculptArgumentError('window', 'has to be a List Type or Tuple Type') # calculate the x-axis (velocity) crpix1 = sxpar(header, "CRPIX1") crval1 = sxpar(header, "CRVAL1") cdelt1 = sxpar(header, "CDELT1") if kms: #convert velocity to km/s crval1 = crval1 / 1000. cdelt1 = cdelt1 / 1000. ctype1 = sxpar(header, "CTYPE1") crpix2 = sxpar(header, "CRPIX2") crval2 = sxpar(header, "CRVAL2") cdelt2 = sxpar(header, "CDELT2") ctype2 = sxpar(header, "CTYPE2") crpix3 = sxpar(header, "CRPIX3") crval3 = sxpar(header, "CRVAL3") cdelt3 = sxpar(header, "CDELT3") ctype3 = sxpar(header, "CTYPE3") nv = sxpar(header, "NAXIS1") nx = sxpar(header, "NAXIS2") ny = sxpar(header, "NAXIS3") blank = sxpar(header, "BLANK") cube = data.copy() if not dontblank and blank is not None: ind = numpy.where(cube == blank) cube[ind] = 0.0 #get velocity axis velax = getaxes(header, 1) indices = numpy.zeros(velax.shape, dtype=bool) for v1, v2 in window: if chan: indices[v1:v2] = True else: ind = numpy.logical_and(velax >= v1, velax <= v2) indices = numpy.logical_or(indices, ind) indices = numpy.logical_not(indices) # for indices to include in std calc rms = cube[:, :, indices].std(axis=2) hnew = header.copy() sxaddpar(hnew, "CRVAL1", crval2, comment="DEGREES") sxaddpar(hnew, "CRPIX1", crpix2) sxaddpar(hnew, "CDELT1", cdelt2, comment="DEGREES") sxaddpar(hnew, "CTYPE1", ctype2) sxaddpar(hnew, "CRVAL2", crval3, comment="DEGREES") sxaddpar(hnew, "CRPIX2", crpix3) sxaddpar(hnew, "CDELT2", cdelt3, comment="DEGREES") sxaddpar(hnew, "CTYPE2", ctype3) sxaddpar(hnew, "NAXIS", 2) sxaddpar(hnew, "NAXIS1", nx) sxaddpar(hnew, "NAXIS2", ny) sxaddpar(hnew, "NAXIS3", 1) sxaddpar(hnew, "NAXIS4", 1) if chan: vorc = 'CHANNEL' else: vorc = 'VELOCITY' sxaddhist(hnew, "WINDOW : %s; Window %s LIMITS" % (repr(window), vorc)) #sxaddpar(hnew, "BUNIT", units, "Units") sxdelpar(hnew, "CRVAL3") sxdelpar(hnew, "CRPIX3") sxdelpar(hnew, "CDELT3") sxdelpar(hnew, "CTYPE3") sxdelpar(hnew, "NAXIS3") sxdelpar(hnew, "NAXIS4") hdu = pyfits.PrimaryHDU(rms, header=hnew) return hdu
def extract_posvel_angle(hdu, p1, angle, header=None, gauss_width=2): """ Given a hdu in vlm format, and one position (in pixel coordinates), and an angle, obtains a position velocity cut about that position with that angle, along that line Returns p-v image as a pyfits hdu unit. @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. If numpy format data cube is passed, then the header parameter should also be passed in. The cube is expected to be in vlm format. @type hdu: pyfits hdu type or numpy nd-array @param p1: (x, y) pixel location of position 1. The x,y position can be a two-tuple, a list of two elements, or numpy array of two elements @type p1: tuple, list or array of floats or ints @param angle: angle of PV cut with respect to X-axis in degrees @type angle: float @param header: pyfits header object if needed @gauss_width: the width of the gaussian kernel to use in weighting neighboring pixels with when extracting spectra @type gauss_width: int @return A HDU instance with 2d position-velocity image in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError('header', "Since you passed in data that is a numpy array, set header to a pyfits header type") data = hdu else: raise SculptArgumentError('hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") hdr = header.copy() dt = data.copy() hdu = pyfits.PrimaryHDU(dt, header=hdr) if gauss_width <= 0 or type(gauss_width) != types.IntType: raise SculptArgumentError('gauss_width', "should be positive and non-zero integer") try: if len(p1) != 2: raise SculptArgumentError('positions', "Positions p1 and p2 should be 2-element tuples, lists or arrays") except: raise SculptArgumentError('positions', "Positions p1 and p2 should be 2-element tuples, lists or arrays") a, b = p1 #x2, y2 = p2 m = math.tan(math.radians(angle)) #slope of line xmin, ymin = 0, 0 y1, x1, v1 = hdu.data.shape ymax = y1-1 xmax = x1-1 print "xylims: ", xmin, ymin, xmax, ymax # #check for x-limits first # xl = None # xh = None # if m > 0.0: # #line sloped right of vertical # yl = m*(xmin-a) + b # else: # #line sloped left of vertical # yl = m*(xmax-a) + b # if ymin <= yl and yl <= ymax: # if m > 0.0: # xl = xmin # else: # xl = xmax # if m > 0.0: # yh = m*(xmax-a) + b # else: # yh = m*(xmin-a) + b # print "yl, yh = ", yl, yh # if ymin <= yh and yh <= ymax: # if m > 0.0: # xh = xmax # else: # xh = xmin # if xl is None: # yl = None # if m > 0.0: # xl = ((ymin-b)/m) + a # else: # xl = ((ymax-b)/m) + a # if xmin <= xl and xl <= xmax: # yl = ymin # if xh is None: # yh = None # if m > 0.0: # xh = ((ymax-b)/m) + a # else: # xh = ((ymin-b)/m) + a # if xmin <= xh and xh <= xmax: # yh = ymax i1, i2 = line_rectangle_intersection(xmin, xmax, ymin, ymax, a, b, angle) xl,yl = i1 xh,yh = i2 print xl, xh, yl, yh d = math.sqrt((xl-xh)**2 + (yl-yh)**2.) posvel = numpy.zeros((int(d), dt.shape[2]), dtype='float') dist = numpy.arange(int(d)) if xl <= xh: x = xl + numpy.sqrt(dist**2./(1+m**2.)) #2nd term is deltax else: x = xl - numpy.sqrt(dist**2./(1+m**2.)) #2nd term is deltax y = yl + m*(x-xl) for i in range(int(d)): posvel[i,:] = extract_spec(hdu, x[i], y[i], gauss_width=gauss_width).data r, d = xyad(header, a, b) sxaddpar(hdr, "CRVAL2", r) dmid = math.sqrt((xl-a)**2 + (yl-b)**2) sxaddpar(hdr, "CRPIX2", int(dmid)) sxaddpar(hdr, "NAXIS", 2) sxdelpar(hdr, "NAXIS3") for name in ('CTYPE', 'CRVAL', 'CDELT', 'CRPIX'): sxdelpar(hdr, "%s3" % name) sxaddhist(hdr, "Extracted posvel image from (%.1f, %.1f) with angle %.2f with gauss_width=%s" % (a, b, angle, gauss_width)) return pyfits.PrimaryHDU(posvel, header=hdr)
def extract_posvel(hdu, p1, p2, header=None, gauss_width=2): """ Given a hdu in vlm format, and two positions (in pixel coordinates), obtains a position velocity cut along that line Returns p-v image as a pyfits hdu unit. @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. If numpy format data cube is passed, then the header parameter should also be passed in. The cube is expected to be in vlm format. @type hdu: pyfits hdu type or numpy nd-array @param p1: (x, y) pixel location of position 1. The x,y position can be a two-tuple, a list of two elements, or numpy array of two elements @type p1: tuple, list or array of floats or ints @param p2: (x, y) pixel location of position 2. The x,y position can be a two-tuple, a list of two elements, or numpy array of two elements @type p2: tuple, list or array of floats or ints @param header: pyfits header object if needed @gauss_width: the width of the gaussian kernel to use in weighting neighboring pixels with when extracting spectra @type gauss_width: int @return A HDU instance with 2d position-velocity image in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError('header', "Since you passed in data that is a numpy array, set header to a pyfits header type") data = hdu else: raise SculptArgumentError('hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") hdr = header.copy() dt = data.copy() hdu = pyfits.PrimaryHDU(dt, header=hdr) if gauss_width <= 0 or type(gauss_width) != types.IntType: raise SculptArgumentError('gauss_width', "should be positive and non-zero integer") try: if len(p1) != 2 and len(p2) != 2: raise SculptArgumentError('positions', "Positions p1 and p2 should be 2-element tuples, lists or arrays") except: raise SculptArgumentError('positions', "Positions p1 and p2 should be 2-element tuples, lists or arrays") x1, y1 = p1 x2, y2 = p2 m = (y1-y2)/(x1-x2) #slope of line d = math.sqrt((x1-x2)**2 + (y1-y2)**2.) posvel = numpy.zeros((int(d), dt.shape[2]), dtype='float') dist = numpy.arange(int(d)) if x1 <= x2: x = x1 + numpy.sqrt(dist**2./(1+m**2.)) #2nd term is deltax else: x = x1 - numpy.sqrt(dist**2./(1+m**2.)) #2nd term is deltax y = y1 + m*(x-x1) for i in range(int(d)): posvel[i,:] = extract_spec(hdu, x[i], y[i], gauss_width=gauss_width).data xmid = (x1+x2)/2. ymid = (y1+y2)/2. r, d = xyad(header, xmid, ymid) sxaddpar(hdr, "CRVAL2", r) mid = posvel.shape[0]/2. sxaddpar(hdr, "CRPIX2", mid) sxaddpar(hdr, "NAXIS", 2) sxdelpar(hdr, "NAXIS3") for name in ('CTYPE', 'CRVAL', 'CDELT', 'CRPIX'): sxdelpar(hdr, "%s3" % name) sxaddhist(hdr, "Extracted posvel image from (%.1f, %.1f) to (%.1f, %.1f) with gauss_width=%s" % (x1, y1, x2, y2, gauss_width)) return pyfits.PrimaryHDU(posvel, header=hdr)
def extract_spec(hdu, x0, y0, header=None, gauss_width=2): """ Given a hdu in vlm format, and a x0,y0 location (in pixel coordinates), obtains a gaussian-convolved spectra around x0, y0 with width gauss_width. Returns spectrum as a pyfits hdu unit as well. @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. If numpy format data cube is passed, then the header parameter should also be passed in. The cube is expected to be in vlm format. @type hdu: pyfits hdu type or numpy nd-array @param x0: x pixel location where spectrum will be centered @type x0: float or int @param y0: y pixel location where spectrum will be centered @type y0: float or int @param header: pyfits header object if needed @gauss_width: the width of the gaussian kernel to use in weighting neighboring pixels with. @type gauss_width: int @return A HDU instance with 1d spectrum map in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError( 'header', "Since you passed in data that is a numpy array, set header to a pyfits header type" ) data = hdu else: raise SculptArgumentError( 'hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") hdr = header.copy() dt = data.copy() if gauss_width <= 0 or type(gauss_width) != types.IntType: raise SculptArgumentError('gauss_width', "should be positive and non-zero integer") gk = gauss_kern(gauss_width) kernx, kerny = gk.shape ysize, xsize, vsize = dt.shape if x0 < 0 or x0 >= xsize: raise SculptArgumentError( 'x0', "x0=%s is out of bounds of x-limits: (0, %d)" % (x0, xsize)) if y0 < 0 or y0 >= ysize: raise SculptArgumentError( 'y0', "y0=%s is out of bounds of y-limits: (0, %d)" % (y0, ysize)) #print gk.shape xmin = int(round(x0)) - kernx / 2 xmax = xmin + kernx if xmin < 0: xmin = 0 if xmax >= xsize: xmax = xsize - 1 ymin = int(round(y0)) - kerny / 2 ymax = ymin + kerny if ymin < 0: ymin = 0 if ymax >= ysize: ymax = ysize - 1 specdata = numpy.zeros(vsize, dtype='float') #print "Gk = " , gk #print xmin, xmax, ymin, ymax #print gk.sum().shape if xmax - xmin != kernx or ymax - ymin != kerny: specdata = dt[y0, x0, :] else: for i in range(vsize): specdata[i] = (gk * dt[ymin:ymax, xmin:xmax, i]).sum() / gk.sum() sxaddpar(hdr, "NAXIS", 1) sxdelpar(hdr, "NAXIS2") sxdelpar(hdr, "NAXIS3") for i in range(2, 4): for name in ('CTYPE', 'CRVAL', 'CDELT', 'CRPIX'): sxdelpar(hdr, "%s%i" % (name, i)) sxaddhist( hdr, "Extracted spectrum at (%s, %s) with gauss_width=%s" % (x0, y0, gauss_width)) return pyfits.PrimaryHDU(specdata, header=hdr)
def mkrmsimage (hdu, window, header=None, chan=False, dontblank=False, kms=True, moment=0): """ Create rms image from spectral cube. The input cube is expected to be in the VLM format @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. This cube is expected to be in vlm format. If numpy format data cube is passed, then the header parameter should also be passed in. @type hdu: pyfits HDU or numpy array @param header: pyfits style header object that corresponds to the hdu data variable. This header parameter is only considered if the hdu parameter is a numpy array type rather than a pyfits HDU type @type header: pyfits header object @param window: list of tuples (pairs) of channels/velocity to exclude from polynomial calculation in determining rms. If chan is set to True, these should be integers. If chan is False, this is expected to be velocity expressed in kms (if the input parameter kms is True). If chan is False, and kms is False, v1 is treated with the same units as the FITS header describes. @param chan: If True, window variables are treated as channels. If False, they are treated as velocity @type chan: Boolean @param dontblank: By default, mkrmsimage will use the BLANK fits header value and automatically zero blanked values in order to compute rms. If dontblank keyword is set, then such blanking is not performed. @type dontblank: Boolean @param kms: If True velocity units is in kms. @type kms: Boolean @return: A HDU instance with 2d output map in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError('header', "Since you passed in data that is a numpy array, set header to a pyfits header type") data = hdu else: raise SculptArgumentError('hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") #check for list or tuple type of window if type(window) not in (types.ListType, types.TupleType): raise SculptArgumentError('window', 'has to be a List Type or Tuple Type') # calculate the x-axis (velocity) crpix1 = sxpar(header,"CRPIX1") crval1 = sxpar(header,"CRVAL1") cdelt1 = sxpar(header,"CDELT1") if kms: #convert velocity to km/s crval1 = crval1/1000. cdelt1 = cdelt1/1000. ctype1 = sxpar(header,"CTYPE1") crpix2 = sxpar(header,"CRPIX2") crval2 = sxpar(header,"CRVAL2") cdelt2 = sxpar(header,"CDELT2") ctype2 = sxpar(header,"CTYPE2") crpix3 = sxpar(header,"CRPIX3") crval3 = sxpar(header,"CRVAL3") cdelt3 = sxpar(header,"CDELT3") ctype3 = sxpar(header,"CTYPE3") nv = sxpar(header,"NAXIS1") nx = sxpar(header,"NAXIS2") ny = sxpar(header,"NAXIS3") blank = sxpar(header,"BLANK") cube = data.copy() if not dontblank and blank is not None: ind = numpy.where(cube == blank) cube[ind] = 0.0 #get velocity axis velax = getaxes(header, 1) indices = numpy.zeros(velax.shape, dtype=bool) for v1, v2 in window: if chan: indices[v1:v2] = True else: ind = numpy.logical_and(velax>= v1, velax<= v2) indices = numpy.logical_or(indices, ind) indices = numpy.logical_not(indices) # for indices to include in std calc rms = cube[:,:,indices].std(axis=2) hnew = header.copy() sxaddpar(hnew, "CRVAL1", crval2, comment="DEGREES") sxaddpar(hnew, "CRPIX1", crpix2) sxaddpar(hnew, "CDELT1", cdelt2, comment="DEGREES") sxaddpar(hnew, "CTYPE1", ctype2) sxaddpar(hnew, "CRVAL2", crval3, comment="DEGREES") sxaddpar(hnew, "CRPIX2", crpix3) sxaddpar(hnew, "CDELT2", cdelt3, comment="DEGREES") sxaddpar(hnew, "CTYPE2", ctype3) sxaddpar(hnew, "NAXIS", 2) sxaddpar(hnew, "NAXIS1", nx) sxaddpar(hnew, "NAXIS2", ny) sxaddpar(hnew, "NAXIS3", 1) sxaddpar(hnew, "NAXIS4", 1) if chan: vorc = 'CHANNEL' else: vorc = 'VELOCITY' sxaddhist(hnew, "WINDOW : %s; Window %s LIMITS" % (repr(window), vorc)) #sxaddpar(hnew, "BUNIT", units, "Units") sxdelpar(hnew, "CRVAL3") sxdelpar(hnew, "CRPIX3") sxdelpar(hnew, "CDELT3") sxdelpar(hnew, "CTYPE3") sxdelpar(hnew, "NAXIS3") sxdelpar(hnew, "NAXIS4") hdu = pyfits.PrimaryHDU(rms, header=hnew) return hdu
def extract_spec(hdu, x0, y0, header=None, gauss_width=2): """ Given a hdu in vlm format, and a x0,y0 location (in pixel coordinates), obtains a gaussian-convolved spectra around x0, y0 with width gauss_width. Returns spectrum as a pyfits hdu unit as well. @param hdu: input pyfits style HDU (header data unit) or just the numpy numpy format data cube from pyfits HDU data attribute. If numpy format data cube is passed, then the header parameter should also be passed in. The cube is expected to be in vlm format. @type hdu: pyfits hdu type or numpy nd-array @param x0: x pixel location where spectrum will be centered @type x0: float or int @param y0: y pixel location where spectrum will be centered @type y0: float or int @param header: pyfits header object if needed @gauss_width: the width of the gaussian kernel to use in weighting neighboring pixels with. @type gauss_width: int @return A HDU instance with 1d spectrum map in the data attribute of the HDU, and the corresponding header in header attribute of the HDU. """ if isinstance(hdu, astropy.io.fits.hdu.image.PrimaryHDU): #get data and header from the hdu data = hdu.data header = hdu.header elif isinstance(hdu, numpy.ndarray): if header is None or not isinstance(header, astropy.io.fits.header.Header): raise SculptArgumentError('header', "Since you passed in data that is a numpy array, set header to a pyfits header type") data = hdu else: raise SculptArgumentError('hdu', "can only be one of pyfits.PrimaryHDU type or numpy ndarray") hdr = header.copy() dt = data.copy() if gauss_width <= 0 or type(gauss_width) != types.IntType: raise SculptArgumentError('gauss_width', "should be positive and non-zero integer") gk = gauss_kern(gauss_width) kernx, kerny = gk.shape ysize, xsize, vsize = dt.shape if x0 < 0 or x0 >= xsize: raise SculptArgumentError('x0', "x0=%s is out of bounds of x-limits: (0, %d)" % (x0, xsize)) if y0 < 0 or y0 >= ysize: raise SculptArgumentError('y0', "y0=%s is out of bounds of y-limits: (0, %d)" % (y0, ysize)) #print gk.shape xmin = int(round(x0))-kernx/2 xmax = xmin+kernx if xmin<0: xmin = 0 if xmax >= xsize: xmax = xsize-1 ymin = int(round(y0))-kerny/2 ymax = ymin+kerny if ymin<0: ymin = 0 if ymax >= ysize: ymax = ysize-1 specdata = numpy.zeros(vsize, dtype='float') #print "Gk = " , gk #print xmin, xmax, ymin, ymax #print gk.sum().shape if xmax-xmin != kernx or ymax-ymin != kerny: specdata = dt[y0, x0, :] else: for i in range(vsize): specdata[i] = (gk*dt[ymin:ymax, xmin:xmax, i]).sum()/gk.sum() sxaddpar(hdr, "NAXIS", 1) sxdelpar(hdr, "NAXIS2") sxdelpar(hdr, "NAXIS3") for i in range(2,4): for name in ('CTYPE', 'CRVAL', 'CDELT', 'CRPIX'): sxdelpar(hdr, "%s%i" % (name, i)) sxaddhist(hdr, "Extracted spectrum at (%s, %s) with gauss_width=%s" % (x0,y0,gauss_width)) return pyfits.PrimaryHDU(specdata, header=hdr)