def pix2world(wcs, x_pix, y_pix): if np.isscalar(x_pix) and np.isscalar(y_pix): x_world, y_world = wcs.wcs_pix2world(np.array([x_pix]), np.array([y_pix]), 1) return x_world[0], y_world[0] elif (type(x_pix) == list) and (type(y_pix) == list): x_world, y_world = wcs.wcs_pix2world(np.array(x_pix), np.array(y_pix), 1) return x_world.tolist(), y_world.tolist() elif isinstance(x_pix, np.ndarray) and isinstance(y_pix, np.ndarray): return wcs.wcs_pix2world(x_pix, y_pix, 1) else: raise Exception("pix2world should be provided either with two scalars, two lists, or two numpy arrays")
def pix_to_skydir(xpix,ypix,wcs): """Convert pixel coordinates to a skydir object.""" if 'RA' in wcs.wcs.ctype[0]: ra, dec = wcs.wcs_pix2world(xpix,ypix,0) return SkyCoord(ra,dec,unit=u.deg) elif 'GLON' in wcs.wcs.ctype[0]: glon, glat = wcs.wcs_pix2world(xpix,ypix,0) return SkyCoord(glon,glat,unit=u.deg, frame='galactic').transform_to('icrs') else: raise Exception('Unrecognized WCS coordinate system.')
def pix2world(wcs, x_pix, y_pix): if np.isscalar(x_pix) and np.isscalar(y_pix): x_world, y_world = wcs.wcs_pix2world(np.array([x_pix]), np.array([y_pix]), 1) return x_world[0], y_world[0] elif (type(x_pix) == list) and (type(y_pix) == list): x_world, y_world = wcs.wcs_pix2world(np.array(x_pix), np.array(y_pix), 1) return x_world.tolist(), y_world.tolist() elif isinstance(x_pix, np.ndarray) and isinstance(y_pix, np.ndarray): return wcs.wcs_pix2world(x_pix, y_pix, 1) else: raise Exception( "pix2world should be provided either with two scalars, two lists, or two numpy arrays" )
def get_asteroid_list_from_fitsfile(fitsfile): hdulist = astropy.io.fits.open(fitsfile) wcs = astropy.wcs.WCS(hdulist[0].header) print wcs.wcs.name # print wcs.wcs.print_contents() # get corner coordinates naxis1, naxis2 = hdulist[0].header['NAXIS1'], hdulist[0].header['NAXIS2'] centerx, centery = naxis1 / 2, naxis2 / 2 center = numpy.array([[centerx, centery]]) print center center_coord = wcs.wcs_pix2world(center, 1) print center_coord epoch = hdulist[0].header['MJD-OBS'] + mjd0 ra = center_coord[0, 0] dec = center_coord[0, 1] sr = 0.4 votab = get_minorobjects(epoch, ra, dec, sr) hdulist.close() return votab
def query_slice(x0, y0, x1, y1, wcs, shape, width=None): nypix, nxpix = shape xpix, ypix = np.meshgrid(np.arange(nxpix), np.arange(nypix)) xpix_world, ypix_world = wcs.wcs_pix2world(xpix.flatten(), ypix.flatten(), 0) if isinstance(width, type(None)): width = np.abs(wcs.wcs.cdelt[1]) m = (y1 - y0) / (x1 - x0) yvec = m * (xpix_world - x0) + y0 xmid = (x1 + x0) / 2. if x1 != x0: xwidth = np.abs(x1 - x0) / 2. else: xwidth = width ymid = (y1 + y0) / 2. if y1 != y0: ywidth = np.abs(y1 - y0) / 2. else: ywidth = width select = (np.abs(yvec - ypix_world) < width) & (np.abs( ypix_world - ymid) < ywidth) & (np.abs(xpix_world - xmid) < xwidth) angular_dist = Coordinates.AngularSeperation(x0, y0, xpix_world[select], ypix_world[select]) return select, xpix_world[select], ypix_world[select], angular_dist
def get_order_wcs(self): # Construct wcs, using each order header for all files self.wcs_outer = [[wcs.WCS(header) for header in hdus] for hdus in self.order_header_outer] # Construct transposed list to loop through spatial dir self.wcs_outer_t = list(map(list, zip(*self.wcs_outer))) # Find number of order elements self.naxis1_list = [header['NAXIS1'] for header in self.order_header_outer[0]] self.naxis2_list = [header['NAXIS2'] for header in self.order_header_outer[0]] # Images must have same number of spatial pixels if not self.naxis2_list.count(self.naxis2_list[0]) == len(self.naxis2_list): raise TypeError("Input image list does not have the same number of spatial pixels.") self.naxis2 = self.naxis2_list[0] self.cdelt1_list = [header['CDELT1'] for header in self.order_header_outer[0]] self.cdelt2_list = [header['CDELT2'] for header in self.order_header_outer[0]] # Images must have same sampling in both directions if not self.cdelt1_list.count(self.cdelt1_list[0]) == len(self.cdelt1_list): raise TypeError("Input image list does not have the same wavelength sampling.") if not self.cdelt2_list.count(self.cdelt2_list[0]) == len(self.cdelt2_list): raise TypeError("Input image list does not have the same spatial sampling.") self.cdelt1 = self.cdelt1_list[0] self.cdelt2 = self.cdelt2_list[0] # Get CRVAL1 for orders self.crval1_list = [header['CRVAL1'] for header in self.order_header_outer[0]] # Get wavelength extent of orders in nm self.start_wave_list = [wcs.wcs_pix2world(1, 1, 1)[0] + 0 for wcs in self.wcs_outer[0]] self.end_wave_list = [wcs.wcs_pix2world(naxis1, 1, 1)[0] + 0 for wcs, naxis1 in zip(self.wcs_outer[0], self.naxis1_list)] # Spatial offset of individual images in arcsec self.cumoff = [header['HIERARCH ESO SEQ CUMOFF Y'] for header in self.order_header_outer_t[0]] # Get spatial extent of orders by looping over the transposed list self.start_size_list = [wcs.wcs_pix2world(1, 1, 1)[1] + self.cumoff[elem] for elem, wcs in enumerate(self.wcs_outer_t[0])] self.end_size_list = [wcs.wcs_pix2world(1, naxis2, 1)[1] + self.cumoff[elem] for elem, (wcs, naxis2) in enumerate(zip(self.wcs_outer_t[0], self.naxis2_list))] # Construct merged wavelength array self.waveaxis_merged = (((np.arange(self.header['NAXIS1'])) + 1 - self.header['CRPIX1'])*self.header['CDELT1']+self.header['CRVAL1'])
def astrometry(self, name, scale): subprocess.call(["/usr/local/astrometry/bin/solve-field", "--cpulimit", "10", "--downsample", "2", "--tweak-order", "2", "--scale-units", "arcsecperpix", "--scale-low", str(numpy.floor(scale*100)/100), "--scale-high", str(numpy.ceil(scale*100)/100), "--no-plots", "--overwrite", name+".ppm"]) if os.path.isfile(name+'.solved'): self.is_solved = True wcs = astropy.wcs.WCS(astropy.io.fits.open(name+'.new')[0].header) self.RA, self.Dec = wcs.wcs_pix2world(self.center_x, self.center_y, 1) else: self.is_solved = False
def make_host(subject, wcs, cache_name, consensus): """Returns an RGZ and SWIRE name for the host, and the location. subject: RGZ subject dict. wcs: World coordinate system (from Astropy). cache_name: Name of Gator cache. consensus: Consensus dict from database. -> (str: RGZ_JHHMMSS-DDMMSS, SWIRE name, RA, DEC) """ # We want RGZ_JHHMMSS-DDMMSS and an associated SWIRE result. Let's start # with the SWIRE result so that the coordinates we get are accurate and # reproducible. Convert pixel coordinates into RA/DEC. x = consensus['source_x'] # Pretty much following willettk's rgz-analysis code here. raise NotImplementedError('Scales have been changed and code not updated.') y = config.get('fits_image_height') - consensus['source_y'] x, y = wcs.wcs_pix2world([x], [y], 1) # Get the closest SWIRE object. p_hosts = data.get_potential_hosts(subject, cache_name, convert_to_px=False) dist_func = distance_from((x, y)) nearest = min(p_hosts, key=dist_func) # Cutoff is in degrees. if not dist_func(nearest) < config.get('swire_distance_cutoff'): raise CatalogueError( 'Closest SWIRE object is not nearby for {}. ' 'Distance: {:.02} degrees'.format( subject['zooniverse_id'], float(dist_func(nearest)))) swire_name = p_hosts[nearest]['name'].decode('ascii') # This provides our coordinates. Separate out HHMMSS/DDMMSS. We can do this # using astropy.coordinates.SkyCoord. Note that I'm using the clon/clat # values returned by Gator; this helps keep us lined up with the SWIRE # coordinates since if you use the RA/DEC raw you get rounding errors. clon = p_hosts[nearest]['clon'].decode('ascii') clat = p_hosts[nearest]['clat'].decode('ascii') coords = astropy.coordinates.SkyCoord(clon + ' ' + clat, unit='deg') ra = coords.ra.hms dec = coords.dec.signed_dms # Construct the name. rgz_name = ('RGZ_J{ra_h:02}{ra_m:02}{ra_s:04.01f}{sign}' '{dec_d:02}{dec_m:02}{dec_s:02}').format( ra_h=int(ra[0]), ra_m=int(ra[1]), ra_s=ra[2], sign='-' if dec[0] < 0 else '+', dec_d=int(dec[1]), dec_m=int(dec[2]), dec_s=int(round(dec[3]))) return rgz_name, swire_name, clon, clat, consensus['location_agreement']
def make_host(subject, wcs, cache_name, consensus): """Returns an RGZ and SWIRE name for the host, and the location. subject: RGZ subject dict. wcs: World coordinate system (from Astropy). cache_name: Name of Gator cache. consensus: Consensus dict from database. -> (str: RGZ_JHHMMSS-DDMMSS, SWIRE name, RA, DEC) """ # We want RGZ_JHHMMSS-DDMMSS and an associated SWIRE result. Let's start # with the SWIRE result so that the coordinates we get are accurate and # reproducible. Convert pixel coordinates into RA/DEC. x = consensus['source_x'] # Pretty much following willettk's rgz-analysis code here. raise NotImplementedError('Scales have been changed and code not updated.') y = config.get('fits_image_height') - consensus['source_y'] x, y = wcs.wcs_pix2world([x], [y], 1) # Get the closest SWIRE object. p_hosts = data.get_potential_hosts(subject, cache_name, convert_to_px=False) dist_func = distance_from((x, y)) nearest = min(p_hosts, key=dist_func) # Cutoff is in degrees. if not dist_func(nearest) < config.get('swire_distance_cutoff'): raise CatalogueError('Closest SWIRE object is not nearby for {}. ' 'Distance: {:.02} degrees'.format( subject['zooniverse_id'], float(dist_func(nearest)))) swire_name = p_hosts[nearest]['name'].decode('ascii') # This provides our coordinates. Separate out HHMMSS/DDMMSS. We can do this # using astropy.coordinates.SkyCoord. Note that I'm using the clon/clat # values returned by Gator; this helps keep us lined up with the SWIRE # coordinates since if you use the RA/DEC raw you get rounding errors. clon = p_hosts[nearest]['clon'].decode('ascii') clat = p_hosts[nearest]['clat'].decode('ascii') coords = astropy.coordinates.SkyCoord(clon + ' ' + clat, unit='deg') ra = coords.ra.hms dec = coords.dec.signed_dms # Construct the name. rgz_name = ('RGZ_J{ra_h:02}{ra_m:02}{ra_s:04.01f}{sign}' '{dec_d:02}{dec_m:02}{dec_s:02}').format( ra_h=int(ra[0]), ra_m=int(ra[1]), ra_s=ra[2], sign='-' if dec[0] < 0 else '+', dec_d=int(dec[1]), dec_m=int(dec[2]), dec_s=int(round(dec[3]))) return rgz_name, swire_name, clon, clat, consensus['location_agreement']
def get_order_information(self): # from astropy import wcs self.norders = int(len(self.hdul) / 3) header_list = [self.hdul[i * 3].header for i in range(self.norders)] wcs_list = [wcs.WCS(header) for header in header_list] self.cdelt1 = header_list[0]['CDELT1'] self.naxis1_list = [header['NAXIS1'] for header in header_list] self.naxis2 = header_list[0]['NAXIS2'] self.start_wave_list = [ wcs.wcs_pix2world(1, 1, 1)[0] for wcs in wcs_list ] self.end_wave_list = [ wcs.wcs_pix2world(naxis1, 1, 1)[0] for wcs, naxis1 in zip(wcs_list, self.naxis1_list) ] self.wcs_list, self.header_list = wcs_list, header_list
def _wcs_toworld (wcs, pixel, wcscale, naxis): # TODO: we don't allow the usage of "SIP" or "Paper IV" # transformations, let alone a concatenation of these, because # they're not invertible. pixel = np.asarray (pixel) if pixel.shape != (naxis, ): raise ValueError ('pixel coordinate must be a %d-element vector', naxis) pixel = pixel.reshape ((1, naxis))[:,::-1] world = wcs.wcs_pix2world (pixel, 0) return world[0,::-1] * wcscale
def _wcs_toworld(wcs, pixel, wcscale, naxis): # TODO: we don't allow the usage of "SIP" or "Paper IV" # transformations, let alone a concatenation of these, because # they're not invertible. pixel = np.asarray(pixel) if pixel.shape != (naxis, ): raise ValueError('pixel coordinate must be a %d-element vector', naxis) pixel = pixel.reshape((1, naxis))[:, ::-1] world = wcs.wcs_pix2world(pixel, 0) return world[0, ::-1] * wcscale
def _footprint(self, pixel_polygon, target, coordsys="J2000d"): """Convert a pixel-space polygon into a sky footprint.""" if coordsys != "J2000d" and coordsys != "Gal": raise NotImplementedError("Unknown coordinate system "+coordsys) # Converts pixel space to WCS-defined sky system wcs = self.get_footprint_wcs(target) sky = wcs.wcs_pix2world(pixel_polygon, 1) # We assume WCS is in J2000d, apply conversion if Galactic is requested if coordsys == "Gal": for i, coord in enumerate(sky): sky[i] = equ2gal(coord) return sky
def calc_pixscale(hdr, ref='crpix', units=None): """Calculate the x and y pixel scales from the WCS information in a FITS header. Parameters ---------- hdr : astropy.io.fits.Header Header object with WCS keywords. Must have the keys 'naxis1', 'naxis2', 'crpix1', 'crpix2', 'crval1', and 'crval1'. ref : {'crpix', 'center', tuple}, optional If 'crpix' (default), the reference pixel is set to CRPIX1,CRPIX2. 'center' indicates that the central pixel in the image should be used. An x,y tuple of floats may be given to use a specific reference pixel instead. units : tuple, optional The units of the longitude and latitude coordinates as a tuple of `astropy.units.core.Unit` instances. If None (default), then the units will be determined from `hdr`. Returns ------- astropy.coordinates.Angle An `Angle` instance containing the x and y pixel scales. Updates ------- added naxis keyword to astropy.wcs.WCS call to ensure only 2 axes are used. - A. R. Lewis 03/30/2015 """ wcs = astropy.wcs.WCS(hdr, naxis=2) if ref == 'crpix': x, y = hdr['crpix1'], hdr['crpix2'] elif ref == 'center': x, y = hdr['naxis1']//2, hdr['naxis2']//2 else: x, y = ref if units is None: units = wcs.wcs.cunit lon, lat = wcs.wcs_pix2world([x, x+1, x], [y, y, y+1], 1) if (astropy.version.major < 1) & (astropy.version.minor < 4): # Makes no difference whether ICRS, Galactic, AltAz, etc. points = astropy.coordinates.ICRS(lon, lat, unit=units) else: # Makes no difference whether ICRS, Galactic, AltAz, etc. points = astropy.coordinates.SkyCoord(lon, lat, frame='icrs', unit=units) dxy = astropy.coordinates.Angle([points[0].separation(points[1]), points[0].separation(points[2])]) return dxy
def query_annullus(x0, y0, r0, r1, wcs, shape): """ """ nypix, nxpix = shape xpix, ypix = np.meshgrid(np.arange(nxpix), np.arange(nypix)) xpix_world, ypix_world = wcs.wcs_pix2world(xpix.flatten(), ypix.flatten(), 0) rpix_world = np.sqrt((xpix_world - x0)**2 * np.cos(ypix_world * np.pi / 180.)**2 + (ypix_world - y0)**2) select = np.where((rpix_world >= r0) & (rpix_world < r1))[0] return select, xpix_world[select], ypix_world[select]
def query_disc(x0, y0, r, wcs, shape): """ """ nypix, nxpix = shape xpix, ypix = np.meshgrid(np.arange(nxpix), np.arange(nypix)) xpix_world, ypix_world = wcs.wcs_pix2world(xpix.flatten(), ypix.flatten(), 0) rpix_world = np.sqrt((xpix_world - x0)**2 * np.cos(ypix_world * np.pi / 180.)**2 + (ypix_world - y0)**2) select = (rpix_world < r) return select, xpix_world[select], ypix_world[select]
def xy_to_radec(wcs, pxy): ''' Convert the x/y coordinates of an image pixel into the ra/dec coordinates of a celestial body :param wcs: a wcs object, as returned by get_wcs() :param pxy: an instance of PixelXY :return: an instance of RaDec ''' pixel = np.array([ [pxy.x, pxy.y], ], np.float_) sky = wcs.wcs_pix2world(pixel, 0) return RaDec(ra=sky[0][0], dec=sky[0][1])
def get_xlim_ylim(x0, y0, width, wcs, shape): nypix, nxpix = shape xpix, ypix = np.meshgrid(np.arange(nxpix), np.arange(nypix)) xpix_world, ypix_world = wcs.wcs_pix2world(xpix, ypix, 0) select = (xpix_world < (x0 + width/2.)) & (xpix_world > (x0 - width/2.)) &\ (ypix_world < (y0 + width/2.)) & (ypix_world > (y0 - width/2.)) xflat = np.where((np.sum(select, axis=0) > 0))[0] yflat = np.where((np.sum(select, axis=1) > 0))[0] return (min(xflat), max(xflat)), (min(yflat), max(yflat)), np.where(select.flatten())[0]
def solver(self, filename): name, extension = os.path.splitext(filename) if extension != '.CR2' and extension != '.avi': self.solve.setEnabled(True) return self.text_line.setText('Converting file into Tiff') if extension == '.CR2': raw = rawpy.imread(filename) image = raw.postprocess(half_size=True) raw.close() imageio.imsave(name + '.tif', image) if extension == '.avi': subprocess.call([ "/usr/bin/avconv", "-i", filename, "-vframes", "1", name + ".jpeg" ]) image = imageio.imread(name + ".jpeg") imageio.imsave(name + '.tif', image) os.remove(name + '.jpeg') center_x = image.shape[1] / 2 center_y = image.shape[0] / 2 self.text_line.setText('Solving image...') scale = float(self.solve_scale.currentText()) subprocess.call([ "/usr/bin/solve-field", "--downsample", "2", "--tweak-order", "2", "--no-plots", "--overwrite", name + ".tif" ]) if not os.path.isfile(name + '.solved'): self.text_line.setText('Image not solved') clean_astrometry(name) self.solve.setEnabled(True) return wcs = astropy.wcs.WCS(astropy.io.fits.open(name + '.new')[0].header) RA, Dec = wcs.wcs_pix2world(center_x, center_y, 1) self.coords = [RA_to_text(RA), Dec_to_text(Dec)] clean_astrometry(name) self.solve.setEnabled(True) self.mount_ip.setEnabled(True) self.mount.setEnabled(True) self.ra_label.setText('Ra: ' + self.coords[0]) self.dec_label.setText('Dec: ' + self.coords[1]) self.text_line.setText('Done')
def plotMap(counts, out='tmp.png', cmap=None, roi=None): """ This method plots some count map. Inherited from the method plotMaps above. :param counts: FITS file with counts to be plotted :param cmap: desired colormap for image :param roi: DS9 region file if present, otherwise leave None :param out: output filename and format :returns: image file 'tmp.png' in the source folder. """ import astropy, astropy.io.fits, astropy.wcs import aplpy def set_hgps_style(f): """Set HGPS style for a f = aplpy.FITSFigure""" f.ticks.set_xspacing(2) f.ticks.set_yspacing(2) f.ticks.set_linewidth(1.5) f.tick_labels.set_xformat('dd') f.tick_labels.set_yformat('dd') f.tick_labels.set_style('colons') f.axis_labels.set_xtext('Right Ascension (deg)') f.axis_labels.set_ytext('Declination (deg)') # Determine image center and width / height dpi = 2000 header = astropy.io.fits.getheader(counts) wcs = astropy.wcs.WCS(header) header['NAXIS1'] / dpi header['NAXIS2'] / dpi lon, lat = header['NAXIS1'] / 2., header['NAXIS2'] / 2. x_center, y_center = wcs.wcs_pix2world(lon, lat, 0) radius = header['CDELT2'] * header['NAXIS2'] / 2. f = aplpy.FITSFigure(counts) f.recenter(x_center, y_center, 0.95 * radius) set_hgps_style(f) f.show_colorscale(stretch='power', exponent=1, cmap=cmap) f.show_colorbar() f.show_markers(x_center, y_center, edgecolor='White', s=400.) if roi != None: f.show_regions(roi) print('Writing {}'.format(out)) pylab.savefig(out)
def plotMap(counts,out='tmp.png',cmap=None,roi=None): """ This method plots some count map. Inherited from the method plotMaps above. :param counts: FITS file with counts to be plotted :param cmap: desired colormap for image :param roi: DS9 region file if present, otherwise leave None :param out: output filename and format :returns: image file 'tmp.png' in the source folder. """ import astropy, astropy.io.fits, astropy.wcs import aplpy def set_hgps_style(f): """Set HGPS style for a f = aplpy.FITSFigure""" f.ticks.set_xspacing(2) f.ticks.set_yspacing(2) f.ticks.set_linewidth(1.5) f.tick_labels.set_xformat('dd') f.tick_labels.set_yformat('dd') f.tick_labels.set_style('colons') f.axis_labels.set_xtext('Right Ascension (deg)') f.axis_labels.set_ytext('Declination (deg)') # Determine image center and width / height dpi = 2000 header = astropy.io.fits.getheader(counts) wcs = astropy.wcs.WCS(header) header['NAXIS1'] / dpi header['NAXIS2'] / dpi lon, lat = header['NAXIS1'] / 2., header['NAXIS2'] / 2. x_center, y_center = wcs.wcs_pix2world(lon, lat, 0) radius = header['CDELT2'] * header['NAXIS2'] / 2. f = aplpy.FITSFigure(counts) f.recenter(x_center, y_center, 0.95 * radius) set_hgps_style(f) f.show_colorscale(stretch='power', exponent=1, cmap=cmap) f.show_colorbar() f.show_markers(x_center, y_center, edgecolor='White', s=400.) if roi!=None: f.show_regions(roi) print('Writing {}'.format(out)) pylab.savefig(out)
def coordinates(image, world=True, lon_sym=True, radians=False): """Get coordinate images for a given image. This function is useful if you want to compute an image with values that are a function of position. Parameters ---------- image : `astropy.io.fits.ImageHDU` world : bool Use world coordinates (or pixel coordinates)? lon_sym : bool Use symmetric longitude range `(-180, 180)` (or `(0, 360)`)? Returns ------- (lon, lat) : tuple of arrays Images as numpy arrays with values containing the position of the given pixel. Examples -------- >>> l, b = coordinates(image) >>> dist = sqrt( (l-42)**2 + (b-43)**2) """ # Create arrays of pixel coordinates y, x = np.indices(image.data.shape, dtype='int32') + 1 if not world: return x, y from astropy.wcs import WCS wcs = WCS(image.header) lon, lat = wcs.wcs_pix2world(x, y, 1) if lon_sym: lon = np.where(lon > 180, lon - 360, lon) if radians: lon = np.radians(lon) lat = np.radians(lat) return lon, lat
def image_segments(header, n): """Generates RA,Dec and yx polygon segments if the image is divided into n-by-n square segments. """ wcs = astropy.wcs.WCS(header) nx = header['NAXIS1'] ny = header['NAXIS2'] dx = int(math.floor(float(nx) / n)) dy = int(math.floor(float(ny) / n)) x0, y0 = 0, 0 for i in xrange(n): x0 = 0 for j in xrange(n): x = [x0, x0, x0 + dx, x0 + dx] y = [y0, y0 + dx, y0 + dy, y0] yx_poly = zip(y, x) ra, dec = wcs.wcs_pix2world(np.array(x), np.array(y), 0) radec_poly = zip(ra, dec) yield radec_poly, yx_poly x0 += dx y0 += dx
def transient_detection(sextractor_output: str, refcat: str, reffed_image: CCDData): image = CCDData.read(reffed_image) wcs = image.wcs gaia = astropy.table.Table( astropy.io.fits.open(refcat)[2].data ) # third hdu, get the numpy recarray, convert to astropy table sex = astropy.table.Table(astropy.io.fits.open(sextractor_output)[2].data) # origin does not seem to really matter... gaia_px = wcs.all_world2pix( np.array(gaia['X_WORLD', 'Y_WORLD'].to_pandas()), 1) gaia['X_IMAGE'] = gaia_px[:, 0] gaia['Y_IMAGE'] = gaia_px[:, 1] # noinspection PyUnusedLocal sex_world = wcs.wcs_pix2world( np.array(sex['XWIN_IMAGE', 'YWIN_IMAGE'].to_pandas()), 1) # noqa # Do calculations in image coordinates so we can use error to estimate same-ness of detections distinct = [] ambig = [] notfound = [] min_starclassifier = 0.8 for row in sex[sex['CLASS_STAR'] > 0.8]: x, y = row['XWIN_IMAGE'], row['YWIN_IMAGE'] xerr, yerr = row['ERRX2WIN_IMAGE'], row['ERRY2WIN_IMAGE'] xcol, ycol = gaia_px[:, 0], gaia_px[:, 1] # how far out of the sextractor reported measurement error for the centroid do we want to search scale = 100 candidate_idx = (xcol > x - xerr * scale) * ( xcol < x + xerr * scale) * (ycol > y - yerr * scale) * ( ycol < y + yerr * scale) n_candidates = sum(candidate_idx) if n_candidates == 1: # check here for brightness difference. Problem right now is that magnitudes have very different offsets distinct.append((row, gaia[candidate_idx])) if n_candidates == 0: # we found a new star???? notfound.append(row) else: ambig.append((row, gaia[candidate_idx])) print('N ClassStar>', min_starclassifier, ':', len(sex[sex['CLASS_STAR'] > 0.8])) print('distinct: ', len(distinct)) print('notfound: ', len(notfound)) print('ambiguous: ', len(ambig)) plt.scatter(gaia_px[:, 0], gaia_px[:, 1], marker='o', color='g', label='reference stars') plt.scatter(sex['XWIN_IMAGE'], sex['YWIN_IMAGE'], color='r', marker='x', label='sextractor') plt.legend() # plt.figure() # plt.scatter([d[0]['XWIN_IMAGE'] for d in distinct], [d[0]['YWIN_IMAGE'] for d in distinct], color='red') # plt.scatter([d[1]['X_IMAGE'] for d in distinct], [d[1]['Y_IMAGE'] for d in distinct], color='green') # plt.scatter([d['XWIN_IMAGE'] for d in notfound], [d['YWIN_IMAGE'] for d in notfound], color='pink') # plt.scatter(gaia['X_WORLD'], gaia['Y_WORLD']) # plt.scatter(sex_world[:, 0], sex_world[:, 1]) plt.show() return sex, gaia
def make_contour_at_level(self,wcs,img,yy,xx,level): C = _cntr.Cntr(xx,yy,img) paths = [p for p in C.trace(level) if p.ndim==2] wcs_paths = [wcs.wcs_pix2world(p,0) for p in paths] return(wcs_paths)
def load_fits2d(self, filename, xy_unit, **hdus): """Load the specified FITS file. The data in each image HDU is interpreted with x mapped to columns (NAXIS1) and y mapped to rows (NAXIS2). The x, y coordinates are inferred from each image HDUs basic WCS parameters. The returned interpolators expect parameter with units and return interpolated values with units. Units for x, y are specified via a parameter and assumed to be the same for all HDUs. Units for the interpolated data are taken from the BUNIT header keyword, and must be interpretable by astropy. Parameters ---------- filename : str Name of the file to read using :meth:`astropy.table.Table.read`. xy_unit : astropy.units.Unit Unit of x, y coordinates. hdus : dict Dictionary of name, hdu mappings where each hdu is specified by its integer offset or its name. Returns ------- dict Dictionary of 2D linear interpolators corresponding to each hdu, with the same keys that appear in the hdus input parameter. """ path = os.path.join(self.abs_base_path, filename) hdu_list = astropy.io.fits.open(path, memmap=False) interpolators = {} for name in hdus: hdu = hdu_list[hdus[name]] ny, nx = hdu.data.shape # Use the header WCS to reconstruct the x,y grids. wcs = astropy.wcs.WCS(hdu.header) x, _ = wcs.wcs_pix2world(np.arange(nx), [0], 0) _, y = wcs.wcs_pix2world([0], np.arange(ny), 0) try: bunit = hdu.header['BUNIT'] data_unit = astropy.units.Unit(bunit) except KeyError: raise KeyError('Missing BUNIT header keyword for HDU {0}.' .format(hdus[name])) except ValueError: raise ValueError('Invalid BUNIT "{0}" for HDU {1}.' .format(bunit, hdus[name])) dimensionless_interpolator = scipy.interpolate.RectBivariateSpline( x, y, hdu.data, kx=1, ky=1, s=0) # Note that the default arg values are used to capture the # current values of dimensionless_interpolator and data_unit # in the closure of this inner function. def interpolator(x, y, f=dimensionless_interpolator, u=data_unit): return f.ev(x.to(xy_unit).value, y.to(xy_unit).value) * u interpolators[name] = interpolator if self.verbose: print('Loaded {0} from HDU[{1}] of {2}.' .format(name, hdus[name], path)) hdu_list.close() return interpolators
def parse_classification(classification, subject, atlas_positions, wcs, pix_offset): """Converts a raw RGZ classification into a classification dict. Scales all positions and flips y axis of clicks. classification: RGZ classification dict. subject: Associated RGZ subject dict. atlas_positions: [[RA, DEC]] NumPy array. wcs: World coordinate system of the ATLAS image. pix_offset: (x, y) pixel position of this radio subject on the ATLAS image. -> dict mapping radio signature to list of corresponding IR host pixel locations. """ result = {} n_invalid = 0 for annotation in classification['annotations']: if 'radio' not in annotation: # This is a metadata annotation and we can ignore it. continue if annotation['radio'] == 'No Contours': # I'm not sure how this occurs. I'm going to ignore it. continue try: radio_signature = make_radio_combination_signature( annotation['radio'], wcs, atlas_positions, subject, pix_offset) except CatalogueError: # Ignore invalid annotations. n_invalid += 1 logging.debug('Ignoring invalid annotation for %s.', subject['zooniverse_id']) continue ir_locations = [] if annotation['ir'] != 'No Sources': for ir_click in annotation['ir']: ir_x = float(annotation['ir'][ir_click]['x']) ir_y = float(annotation['ir'][ir_click]['y']) # Rescale to a consistent size. ir_x *= config['surveys']['atlas']['click_to_fits_x'] ir_y *= config['surveys']['atlas']['click_to_fits_y'] # Ignore out-of-range data. if not 0 <= ir_x <= config['surveys']['atlas']['fits_width']: n_invalid += 1 continue if not 0 <= ir_y <= config['surveys']['atlas']['fits_height']: n_invalid += 1 continue # Flip the y axis to match other data conventions. ir_y = config['surveys']['atlas']['fits_height'] - ir_y # Rescale to match the mosaic WCS. ir_x *= config['surveys']['atlas']['mosaic_scale_x'] ir_y *= config['surveys']['atlas']['mosaic_scale_y'] # Move to the reference location of the radio subject. ir_x += pix_offset[0] ir_y += pix_offset[1] # Convert the location into RA/DEC. (ir_x,), (ir_y,) = wcs.wcs_pix2world([ir_x], [ir_y], 1) ir_location = (ir_x, ir_y) ir_locations.append(ir_location) result[radio_signature] = ir_locations if n_invalid: logging.debug('%d invalid annotations for %s.', n_invalid, subject['zooniverse_id']) return result
def get_contours(self, fitsfile, Ak=None): """ Given a continuum FITS file, return the contours enclosing the source position at a given flux level. There are a couple complications: 1) We seek a closed contour 2) The contour should only extend over the region covered by the NIR image (K-band, in this case) This function could usefully be refactored/simplified """ hdulist = fits.open(fitsfile) header = hdulist[0].header img = hdulist[0].data if not Ak: contour_level = self.contour_level #10 av in Jy? print("Using a contour level of: "+str(round(contour_level,3))) else: contour_level = self.calculate_continuum_level( cont_survey=self.cont_survey, Ak=Ak) print("Using a contour level of: "+str(round(contour_level,3))) wcs = pywcs.WCS(header) yy,xx = np.indices(img.shape) img[img!=img] = 0 #Set the borders of an image to be zero (blank) so that all contours close img[0,:] = 0.0 img[-1,:] = 0.0 img[:,0] = 0.0 img[:,-1] = 0.0 self.all_contours = [] #for contour_level in contour_levels: wcs_paths = self.make_contour_at_level(wcs,img,yy,xx,contour_level) # self.all_contours.append(np.array(wcs_paths)) index = 0 self.good_contour = False print(self.glon,self.glat) if len(wcs_paths) > 1: print("More than one contour") for i,wcs_path in enumerate(wcs_paths): path = Path(wcs_path) #print(path) if path.contains_point((self.glon,self.glat)): index = i self.good_contour = True print("This was the contour containing the center") #index = 1 #self.good_contour = True self.contours = wcs_paths[index] #self.contours[:,0] -= 0.02 #self.contours[:,1] += 0.02 #print(self.contours[:,1]) else: self.good_contour = True self.contours = wcs_paths[0] #This selects a contour containing the center #Now we trim the contour to the boundaries of the UKIDSS image if self.good_contour: #And check to see which contour (if any) contains the center self.good_contour = False #Find the boundaries of the UKIDSS (K-band image) in Galactic coordinates h = fits.getheader(self.kim) xmin = 0 xmax = h['NAXIS1'] ymin = 0 ymax = h['NAXIS2'] wcs = pywcs.WCS(h) corners = wcs.wcs_pix2world([[xmin,ymin],[xmin,ymax],[xmax,ymax],[xmax,ymin]],0) gals = [] for coord in corners: c = coordinates.ICRS(ra=coord[0],dec=coord[1],unit=[u.deg,u.deg]) gal = c.transform_to(coordinates.Galactic) gals.append(gal) mycoords = [] for gal in gals: l,b = gal.l.degree,gal.b.degree mycoords.append((l,b)) p1 = shapely.geometry.Polygon(self.contours) p1 = p1.buffer(0) #print(p1.is_valid) p2 = shapely.geometry.Polygon(mycoords) p2.buffer(0) #print(p2.is_valid) ya = p1.intersection(p2) #print(ya) try: mycontours = [] xx,yy = ya.exterior.coords.xy for ix,iy in zip(xx,yy): mycontours.append((ix,iy)) self.contours = np.array(mycontours) self.good_contour = True except AttributeError: #MultiPolygon mycontours = [] for j,poly in enumerate(ya): try: #print(poly) yoyo = np.asarray(poly.exterior.coords.xy) #print(yoyo.shape) #print(yoyo) yoyo2 = yoyo.T #print(poly.exterior.coords.xy) #yya = poly.exterior.coords.xy[0] #print(yya.shape) #print(yoyo2) path = Path(yoyo2) if path.contains_point((self.glon,self.glat)): self.good_contour = True index = i print("This was the contour containing the center") xx,yy = poly.exterior.coords.xy for ix,iy in zip(xx,yy): mycontours.append((ix,iy)) self.contours = np.array(mycontours) except IOError: pass self.contour_area = self.calc_contour_area(self.contours) if not self.good_contour: print("######## No good contour found ########") self.contours = None self.contour_area = 0
def parse_classification(classification, subject, atlas_positions, wcs, pix_offset): """Converts a raw RGZ classification into a classification dict. Scales all positions and flips y axis of clicks. classification: RGZ classification dict. subject: Associated RGZ subject dict. atlas_positions: [[RA, DEC]] NumPy array. wcs: World coordinate system of the ATLAS image. pix_offset: (x, y) pixel position of this radio subject on the ATLAS image. -> dict mapping radio signature to list of corresponding IR host pixel locations. """ result = {} n_invalid = 0 for annotation in classification['annotations']: if 'radio' not in annotation: # This is a metadata annotation and we can ignore it. continue if annotation['radio'] == 'No Contours': # I'm not sure how this occurs. I'm going to ignore it. continue try: radio_signature = make_radio_combination_signature( annotation['radio'], wcs, atlas_positions, subject, pix_offset) except CatalogueError: # Ignore invalid annotations. n_invalid += 1 logging.debug('Ignoring invalid annotation for %s.', subject['zooniverse_id']) continue ir_locations = [] if annotation['ir'] != 'No Sources': for ir_click in annotation['ir']: ir_x = float(annotation['ir'][ir_click]['x']) ir_y = float(annotation['ir'][ir_click]['y']) # Rescale to a consistent size. ir_x *= config['surveys']['atlas']['click_to_fits_x'] ir_y *= config['surveys']['atlas']['click_to_fits_y'] # Ignore out-of-range data. if not 0 <= ir_x <= config['surveys']['atlas']['fits_width']: n_invalid += 1 continue if not 0 <= ir_y <= config['surveys']['atlas']['fits_height']: n_invalid += 1 continue # Flip the y axis to match other data conventions. ir_y = config['surveys']['atlas']['fits_height'] - ir_y # Rescale to match the mosaic WCS. ir_x *= config['surveys']['atlas']['mosaic_scale_x'] ir_y *= config['surveys']['atlas']['mosaic_scale_y'] # Move to the reference location of the radio subject. ir_x += pix_offset[0] ir_y += pix_offset[1] # Convert the location into RA/DEC. (ir_x, ), (ir_y, ) = wcs.wcs_pix2world([ir_x], [ir_y], 1) ir_location = (ir_x, ir_y) ir_locations.append(ir_location) result[radio_signature] = ir_locations if n_invalid: logging.debug('%d invalid annotations for %s.', n_invalid, subject['zooniverse_id']) return result
https://qiita.com/nishimuraatsushi/items/f422c624027dcd34b820 @author: PC """ import numpy import astropy.coordinates 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' ) header = fits[0].header data = fits[0].data maxind = numpy.unravel_index(numpy.nanargmax(data), data.shape) wcs = astropy.wcs.WCS(fits[0].header) maxworld = wcs.wcs_pix2world([maxind[::-1]], 0) # wcs_pix2world の要求するインデックスの軸の順は x, y(, z) # fits[0].data の軸の順は、(z,) y, x # この 2 つの向きが逆なので、maxind[::-1] で反転させている galx, galy = maxworld[0] # >>> (208.99999963578261, -19.383371004831144) # 銀河座標で作成 coord = astropy.coordinates.SkyCoord(galx, galy, frame='galactic', unit='deg') # >>> <SkyCoord (Galactic): (l, b) in deg # (208.99999964, -19.383371)> # 星座を確認 coord.get_constellation()
def plotMaps(configfile="analysis.conf", cmap=None): """ Given the directory where the results of an Enrico analysis are located (enrico_sed), this method plots the different count maps (observed, model and residuals). This is the fixed version of the script plotMaps.py from the Enrico distribution. :param configdir: directory with "/" at the end that points to the place where Enrico output files are located. :returns: image file SOURCE_Maps.png in the source folder. """ import astropy, astropy.io.fits, astropy.wcs import aplpy config, c = getconfig(configfile) def set_hgps_style(f): """Set HGPS style for a f = aplpy.FITSFigure""" f.ticks.set_xspacing(2) f.ticks.set_yspacing(2) f.ticks.set_linewidth(1.5) f.tick_labels.set_xformat('dd') f.tick_labels.set_yformat('dd') f.tick_labels.set_style('colons') f.axis_labels.set_xtext('Right Ascension (deg)') f.axis_labels.set_ytext('Declination (deg)') # Determine image center and width / height dpi = 2000 header = astropy.io.fits.getheader(c['cmapfile']) wcs = astropy.wcs.WCS(header) header['NAXIS1'] / dpi header['NAXIS2'] / dpi lon, lat = header['NAXIS1'] / 2., header['NAXIS2'] / 2. x_center, y_center = wcs.wcs_pix2world(lon, lat, 0) radius = header['CDELT2'] * header['NAXIS2'] / 2. # Computing the sub-figure sizes is surprisingly hard figsize = (5, 15) figure = pylab.figure(figsize=figsize) axis_ratio = figsize[0] / float(figsize[1]) edge_margin_x = 0.12 edge_margin_y = edge_margin_x * axis_ratio edge_margin_x_up = 0.01 edge_margin_y_up = edge_margin_x_up * axis_ratio inner_margin_x = 0.1 inner_margin_y = inner_margin_x * axis_ratio size_x = (1 - edge_margin_x - edge_margin_x_up) size_y = (1 - edge_margin_y - edge_margin_y_up - 2 * inner_margin_y) / 3 for i, image in enumerate(c['images']): subplot = [ edge_margin_x, edge_margin_y + i * (size_y + inner_margin_y), size_x, size_y ] f = aplpy.FITSFigure(image, figure=figure, subplot=subplot) f.recenter(x_center, y_center, 0.95 * radius) set_hgps_style(f) f.show_colorscale(stretch='power', exponent=1, cmap=cmap) #f.show_colorbar() if i == 0: f.show_markers(x_center, y_center, edgecolor='Black', s=400.) if i == 1: f.show_markers(x_center, y_center, edgecolor='White', s=400.) f.show_regions(c['folder'] + '/Roi_model.reg') if i == 2: f.show_markers(x_center, y_center, edgecolor='Black', s=400.) plotfile = c['folder'] + "/" + config['target']['name'] + "_Maps.png" print('Writing {}'.format(plotfile)) figure.savefig(plotfile)
def make_contour_at_level(self, wcs, img, yy, xx, level): C = _cntr.Cntr(xx, yy, img) paths = [p for p in C.trace(level) if p.ndim == 2] wcs_paths = [wcs.wcs_pix2world(p, 0) for p in paths] return (wcs_paths)
def _extract_star_sequence(self, imfile, survey='ps1', minmag=14.5, maxmag=20, plot=True, debug=False): ''' Given a fits image: imfile and a the name of the band which we want to extract the sources from, it saves the extracted sources into '/tmp/sdss_cat_det.txt' file. If the band does not match the bands in the survey, a change is performed to adapt to the new band. If plotting activated, plots the USNOB1 field of stars on top of the star field image. Red circles are stars identified from the catalogue in the correct magnitude range. Yellow circles are stars that are isolated. Parameters: ----------- imfile: str Name of the file to be calibrated. survey: str Name of the survey to be used for zeropoint calibration. By default is PS1. minmag: int. Default 14.5 mag The brightest mangitude that will be retrieved from the catalogues. maxmag: int. Default 20.0 mag The faintest mangitude that will be retrieved from the catalogues. plot: boolean Boolean for plotting the zeropoint calibation plots in the plot directory. debug: boolean. Default False. Boolean to show debug additional plots in the plot directory. ''' f = fits.open(imfile) survey = survey.upper() #Extract the filter fheader = f[self.ext].header['FILTER'] band = self.filter_dic.get(fheader, fheader) #Extract the WCS wcs = astropy.wcs.WCS(f[self.ext].header) #Extract the pixel scale pix2ang = f[self.ext].header[self.pixscale_keyword] #Extract the data img = f[self.ext].data #Assume that negative values shall be corrected img[img<0] = 0 #Compute the ra, dec of the centre of the filed and the edges ra, dec = wcs.wcs_pix2world(np.array([img.shape[0]/2, img.shape[1]/2], ndmin=2), 1)[0] ra0, dec0 = wcs.wcs_pix2world(np.array([img.shape[0], img.shape[1]], ndmin=2), 1)[0] #Calculate the size of the field --> search radius . As maximum, it needs to be 0.25 deg. sr = 2.1*np.abs(dec-dec0) sr = np.minimum(sr, 0.5) self.logger.info("Field center: (%.4f %.4f) and FoV: %.4f [arcmin] "%( ra, dec, sr*60)) #Creates the Query class qc = QueryCatalogue.QueryCatalogue(ra, dec, sr/1.8, minmag, maxmag, self.logger) cat_file = os.path.join(self._tmppath, 'query_result_%s_%.6f_%.6f_%.5f_%.2f_%.2f.txt'%(survey.split("/")[-1], ra, dec, sr, minmag, maxmag) ) detected_stars_file = os.path.join(self._tmppath, 'detected_result_%s_%.6f_%.6f_%.5f_%.2f_%.2f.txt'%(survey.split("/")[-1], ra, dec, sr, minmag, maxmag) ) #Check if the query already exists in our tmp directory, #so we do not need to query it again. if (os.path.isfile(cat_file)): self.logger.info("File %s already exists. Loading it."%cat_file) catalog = Table.read(cat_file, format="ascii") #If that is not the case, then we check if the catalogue is in one of the lists provided by VO portal else: self.logger.info("File %s does not exist. Querying it."%cat_file) if (np.any( np.array(['GSC23', 'GSC11', 'GSC12', 'USNOB', 'SDSS', 'FIRST', '2MASS', 'IRAS', 'GALEX', 'GAIA', 'TGAS', 'WISE', \ 'CAOM_OBSCORE', 'CAOM_OBSPOINTING', 'PS1V3OBJECTS', 'PS1V3DETECTIONS'])==survey)): catalog = qc.query_catalogue(catalogue=survey, filtered=True) #But it can be a SkyMapper as well (in the south). elif (survey == 'SKYMAPPER'): catalog = qc.query_sky_mapper(filtered=True) #More services can be added here, but at the moment, if the survey is none of the # above, the we paunch an error. else: self.logger.warn("Survey %s not recognized. Trying to query Vizier for that."%survey) try: catalog = qc.query_vizier(catalog=survey) except: self.logger.error("Unknown survey %s"%survey) return None if (np.ndim(catalog)==0 or catalog is None): return False else: catalog = Table(data=catalog) #if ( np.all(catalog[band].mask )): # self.logger.error( "All magntiudes for filter %s are masked!"% band) # return False #else: # catalog = catalog[~catalog[band].mask] try: #Rename the columns, so that the filters match our standard. for n in catalog.colnames: if n in self.filter_dic.keys(): catalog.rename_column(n, self.filter_dic[n]) except IOError: self.logger.error( "Problems with catalogue IO %s"% band) return False except ValueError: self.logger.error( "Problems with the catalogue for the image") return False # Determine the X and Y of all the stars in the query. catcoords = astropy.coordinates.SkyCoord( catalog['ra'], catalog['dec'], unit=u.deg) self.logger.info("Catalogue has %d entries"%len(catcoords)) #Convert ra, dec position of all stars to pixels. pixcoord = wcs.all_world2pix( np.array([catalog['ra'], catalog['dec']]).T, 1) x = pixcoord.T[0] y = pixcoord.T[1] #Select only the stars within the image (and within an offset of 15 arcsec (in pixels) from the border.) off = math.ceil(15/pix2ang) mask1 = (x>off) * (x<img.shape[1]-off)*(y>off) * (y<img.shape[0]-off) #Select only stars isolated in a radius of ~10 arcsec. Cross match against itself and select the second closest. indexes, separations, distances = catcoords.match_to_catalog_sky(catcoords, nthneighbor=2) mask2 = (separations > 10 * u.arcsec) #Select the right magnitude range mask3 = (catalog[band]>minmag)*(catalog[band]<maxmag) #Combine all masks mask = mask1 * mask2 * mask3 if (not np.any(mask)): self.logger.warn("No good stars left with current conditions.") return False #Otherwise, it means there are good stars left catalog = catalog[mask] self.logger.info("Catalog length after masking: %d"%len(catalog)) self.logger.debug("Left %d stars."%(len(catalog))) z = np.zeros(len(catalog), dtype=[('xpos', np.float), ('ypos',np.float)]) z['xpos'] = x[mask] z['ypos'] = y[mask] #Iteratively create a header to store catalogue data for selected stars #only the relevant fields. catalog_det = Table(data=z, names=['xpos', 'ypos']) for n in catalog.colnames: if ((n in ["objid", "ra", "dec", "u", "g", "r", "i", "z", "y", "du", "dg", "dr", "di", "dz", "dy"]) or (n in ['id', 'ra', 'dec', 'U', 'B', 'V', 'R', 'I', 'dU', 'dB', 'dV', 'dR', 'dI'] )): catalog_det.add_column(catalog[n]) catalog_det.write(cat_file, format="ascii.csv", overwrite=True) self.logger.info( "Saved catalogue stars to %s"%cat_file ) #Find FWHM for this image out = self._find_fwhm(imfile, catalog_det['xpos'], catalog_det['ypos'], plot=debug) with warnings.catch_warnings(): warnings.simplefilter("ignore") mask_valid_fwhm = ( ~np.isnan(out['fwhm']) * ~np.isnan(out['e']) * out['detected'] * (out['e']>0.6) * (out['fwhm'] < 10)) self.logger.info("Left %d stars with valid fwhm."%np.count_nonzero(mask_valid_fwhm)) if (np.count_nonzero(mask_valid_fwhm) < 3): self.logger.error( "ERROR with FWHM!! Too few points for a valid estimation. %d"% np.count_nonzero(mask_valid_fwhm)+ ") points") return False #Add the FWHM of each detection to the detected stars list outd = out[mask_valid_fwhm] catalog_det = catalog_det[mask_valid_fwhm] fwhm = Column(data=outd['fwhm']*pix2ang, name='fwhm') catalog_det.add_column(fwhm) #Write it to the header as well fitsutils.update_par(imfile, "FWHM", np.median(outd['fwhm']*pix2ang), ext=self.ext) catalog_det.write(detected_stars_file, format="ascii", overwrite=True) self.logger.info( 'Average FWHM %.1f pixels, %.3f arcsec'%(np.median(outd['fwhm']), np.median(outd['fwhm'])*pix2ang)) self.logger.info( "Found %d stars in %s. "%(len(catalog), survey)+ \ "%d of them are isolated."%np.count_nonzero(mask2)+\ "%d of them within the FoV. "%np.count_nonzero(mask) +\ "%d of them with detected stars."%np.count_nonzero(mask_valid_fwhm)) if (plot): #Plot results img = img - np.nanmin(img) zmin = np.percentile(img, 5) zmax = np.percentile(img, 95) plt.figure(figsize=(12,12)) im = plt.imshow(img, aspect="equal", origin="lower", cmap=matplotlib.cm.gray_r, vmin=zmin, vmax=zmax) selected_x = catalog_det['xpos'] selected_y = catalog_det['ypos'] if (len(selected_x) >0): plt.scatter(selected_x, selected_y, marker="o", s=400, \ edgecolor="blue", facecolor="none", label="detected") plt.legend(loc="best", frameon=False, framealpha=0.9) plt.title("Selected stars for filter %s"%band) extension = os.path.basename(imfile).split(".")[-1] figname = os.path.join( self._plotpath, os.path.basename(imfile).replace(extension, 'seqstars.png')) plt.savefig( figname) self.logger.info( "Saved stars to %s"%figname) plt.clf() return detected_stars_file
# -*- coding: utf-8 -*- """ Created on Thu May 28 22:44:39 2020 @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) # 画像座標系[pix]→WCS[geg]変換 print(wcs.wcs_pix2world([[0, 0]], 0)) print(wcs.wcs_pix2world([[100, 50]], 0)) print(wcs.wcs_pix2world([[200, 100]], 0)) print(wcs.wcs_pix2world([[300, 150]], 0)) print(wcs.wcs_pix2world([[400, 200]], 0)) print(wcs.wcs_pix2world([[500, 250]], 0)) print(wcs.wcs_pix2world([[600, 300]], 0)) print(wcs.wcs_pix2world([[700, 350]], 0))
def plotMaps(configfile="analysis.conf",cmap=None): """ Given the directory where the results of an Enrico analysis are located (enrico_sed), this method plots the different count maps (observed, model and residuals). This is the fixed version of the script plotMaps.py from the Enrico distribution. :param configdir: directory with "/" at the end that points to the place where Enrico output files are located. :returns: image file SOURCE_Maps.png in the source folder. """ import astropy, astropy.io.fits, astropy.wcs import aplpy config,c=getconfig(configfile) def set_hgps_style(f): """Set HGPS style for a f = aplpy.FITSFigure""" f.ticks.set_xspacing(2) f.ticks.set_yspacing(2) f.ticks.set_linewidth(1.5) f.tick_labels.set_xformat('dd') f.tick_labels.set_yformat('dd') f.tick_labels.set_style('colons') f.axis_labels.set_xtext('Right Ascension (deg)') f.axis_labels.set_ytext('Declination (deg)') # Determine image center and width / height dpi = 2000 header = astropy.io.fits.getheader(c['cmapfile']) wcs = astropy.wcs.WCS(header) header['NAXIS1'] / dpi header['NAXIS2'] / dpi lon, lat = header['NAXIS1'] / 2., header['NAXIS2'] / 2. x_center, y_center = wcs.wcs_pix2world(lon, lat, 0) radius = header['CDELT2'] * header['NAXIS2'] / 2. # Computing the sub-figure sizes is surprisingly hard figsize=(5, 15) figure = pylab.figure(figsize=figsize) axis_ratio = figsize[0] / float(figsize[1]) edge_margin_x = 0.12 edge_margin_y = edge_margin_x * axis_ratio edge_margin_x_up = 0.01 edge_margin_y_up = edge_margin_x_up * axis_ratio inner_margin_x = 0.1 inner_margin_y = inner_margin_x * axis_ratio size_x = (1 - edge_margin_x - edge_margin_x_up) size_y = (1 - edge_margin_y - edge_margin_y_up - 2 * inner_margin_y) / 3 for i, image in enumerate(c['images']): subplot = [edge_margin_x, edge_margin_y + i * (size_y + inner_margin_y), size_x, size_y] f = aplpy.FITSFigure(image, figure=figure, subplot=subplot) f.recenter(x_center, y_center, 0.95 * radius) set_hgps_style(f) f.show_colorscale(stretch='power', exponent=1, cmap=cmap) #f.show_colorbar() if i==0: f.show_markers(x_center, y_center, edgecolor='Black', s=400.) if i==1: f.show_markers(x_center, y_center, edgecolor='White', s=400.) f.show_regions(c['folder']+'/Roi_model.reg') if i==2: f.show_markers(x_center, y_center, edgecolor='Black', s=400.) plotfile =c['folder']+"/"+config['target']['name']+"_Maps.png" print('Writing {}'.format(plotfile)) figure.savefig(plotfile)
def problem_2(results, **kwargs): verbose = kwargs.get('verbose', False) # Determine pixel area in arcsec2 header = results['header'] wcs = astropy.wcs.WCS(header) x, y = np.array([header['crpix1'], header['crpix2']]) ra, dec = wcs.wcs_pix2world([x, x+1, x], [y, y, y+1], 1) points = astropy.coordinates.SkyCoord(ra, dec, 'icrs', unit=wcs.wcs.cunit) dxy = astropy.coordinates.Angle([points[0].separation(points[1]), points[0].separation(points[2])]) pixel_scales = dxy.arcsec pixel_area = pixel_scales[0] * pixel_scales[1] results['pixel_scales'], results['pixel_area'] = pixel_scales, pixel_area # Photometry radius_mult = 1.5 # Size of inner radius wrt aperture (factor) dr = 50.0 # Size of outer radius wrt inner (offset in pixels) aperture_list = results['apertures_#1'] image = results['image'] annulus_list = [] for aperture in aperture_list: xy0 = aperture.xy0 r1 = radius_mult * aperture.r r2 = r1 + dr annulus = galaxyphot.CircularAnnulus(xy0, r1, r2, label=aperture.label) annulus_list.append(annulus) apphot = galaxyphot.apphot(image, aperture_list) anphot = galaxyphot.apphot(image, annulus_list) # Intensities, counts/pixel intensity_tot = apphot['mean'] # Same as total/area intensity_bg = anphot['median'] intensity = intensity_tot - intensity_bg err = np.sqrt(intensity_tot * apphot['area'] + intensity_bg * anphot['area']) / apphot['area'] # Intensities, counts/arcsec2 intensity /= pixel_area err /= pixel_area results['intensity_bgannulus'] = intensity_bg / pixel_area if verbose: print ( 'Photometry:\n' '\n' '======= ============= ========\n' 'galaxy intensity err\n' ' (cnt/arcsec2)\n' '======= ============= ========' ) for i, label in enumerate(apphot['label']): vals = (label, intensity[i], err[i]) print '{0:7s} {1:13.2e} {2:8.2e}'.format(*vals) print '======= ============= ========\n\n' """ Photometry: ======= ============= ======== galaxy intensity err (cnt/arcsec2) ======= ============= ======== NGC4875 1.73e+03 7.69e+00 NGC4869 5.64e+03 1.08e+01 GMP4277 2.69e+03 5.59e+00 GMP4350 2.19e+03 5.54e+00 NGC4860 4.84e+03 7.79e+00 NGC4881 1.66e+03 2.37e+00 NGC4921 7.39e+02 4.91e-01 ======= ============= ======== """ return results
err=error[freq], returnmp=True, rotate=True, vheight=True, circle=False, returnfitimage=True) except: mpfits[freq][name] = () gpars[freq][name] = np.array([np.nan]*7) gparerrs[freq][name] = np.array([np.nan]*7) continue mpfits[freq][name] = mp gpars[freq][name] = mp.params gparerrs[freq][name] = mp.perror gfits[freq][name] = fitimg wcsX,wcsY = wcs.wcs_pix2world(mp.params[2]+int(xc-3*rp), mp.params[3]+int(yc-3*rp), 0) center_coord = coordinates.SkyCoord(wcsX*u.deg, wcsY*u.deg, frame=wcs.wcs.radesys.lower()) gpars[freq][name][2] = center_coord.transform_to('fk5').ra.deg gpars[freq][name][3] = center_coord.transform_to('fk5').dec.deg gpars[freq][name][4] *= pixscale.to(u.deg).value gpars[freq][name][5] *= pixscale.to(u.deg).value gparerrs[freq][name][2] *= pixscale.to(u.deg).value gparerrs[freq][name][3] *= pixscale.to(u.deg).value gparerrs[freq][name][4] *= pixscale.to(u.deg).value gparerrs[freq][name][5] *= pixscale.to(u.deg).value else: peaks[freq][name] = np.nan valleys[freq][name] = np.nan
def get_contours(self, fitsfile, Ak=None): """ Given a continuum FITS file, return the contours enclosing the source position at a given flux level. There are a couple complications: 1) We seek a closed contour 2) The contour should only extend over the region covered by the NIR image (K-band, in this case) This function could usefully be refactored/simplified """ hdulist = fits.open(fitsfile) header = hdulist[0].header img = hdulist[0].data if not Ak: contour_level = self.contour_level #10 av in Jy? print("Using a contour level of: " + str(round(contour_level, 3))) else: contour_level = self.calculate_continuum_level( cont_survey=self.cont_survey, Ak=Ak) print("Using a contour level of: " + str(round(contour_level, 3))) wcs = pywcs.WCS(header) yy, xx = np.indices(img.shape) img[img != img] = 0 #Set the borders of an image to be zero (blank) so that all contours close img[0, :] = 0.0 img[-1, :] = 0.0 img[:, 0] = 0.0 img[:, -1] = 0.0 self.all_contours = [] #for contour_level in contour_levels: wcs_paths = self.make_contour_at_level(wcs, img, yy, xx, contour_level) # self.all_contours.append(np.array(wcs_paths)) index = 0 self.good_contour = False print(self.glon, self.glat) if len(wcs_paths) > 1: print("More than one contour") for i, wcs_path in enumerate(wcs_paths): path = Path(wcs_path) #print(path) if path.contains_point((self.glon, self.glat)): index = i self.good_contour = True print("This was the contour containing the center") #index = 1 #self.good_contour = True self.contours = wcs_paths[index] #self.contours[:,0] -= 0.02 #self.contours[:,1] += 0.02 #print(self.contours[:,1]) else: self.good_contour = True self.contours = wcs_paths[0] #This selects a contour containing the center #Now we trim the contour to the boundaries of the UKIDSS image if self.good_contour: #And check to see which contour (if any) contains the center self.good_contour = False #Find the boundaries of the UKIDSS (K-band image) in Galactic coordinates h = fits.getheader(self.kim) xmin = 0 xmax = h['NAXIS1'] ymin = 0 ymax = h['NAXIS2'] wcs = pywcs.WCS(h) corners = wcs.wcs_pix2world( [[xmin, ymin], [xmin, ymax], [xmax, ymax], [xmax, ymin]], 0) gals = [] for coord in corners: c = coordinates.ICRS(ra=coord[0], dec=coord[1], unit=[u.deg, u.deg]) gal = c.transform_to(coordinates.Galactic) gals.append(gal) mycoords = [] for gal in gals: l, b = gal.l.degree, gal.b.degree mycoords.append((l, b)) p1 = shapely.geometry.Polygon(self.contours) p1 = p1.buffer(0) #print(p1.is_valid) p2 = shapely.geometry.Polygon(mycoords) p2.buffer(0) #print(p2.is_valid) ya = p1.intersection(p2) #print(ya) try: mycontours = [] xx, yy = ya.exterior.coords.xy for ix, iy in zip(xx, yy): mycontours.append((ix, iy)) self.contours = np.array(mycontours) self.good_contour = True except AttributeError: #MultiPolygon mycontours = [] for j, poly in enumerate(ya): try: #print(poly) yoyo = np.asarray(poly.exterior.coords.xy) #print(yoyo.shape) #print(yoyo) yoyo2 = yoyo.T #print(poly.exterior.coords.xy) #yya = poly.exterior.coords.xy[0] #print(yya.shape) #print(yoyo2) path = Path(yoyo2) if path.contains_point((self.glon, self.glat)): self.good_contour = True index = i print("This was the contour containing the center") xx, yy = poly.exterior.coords.xy for ix, iy in zip(xx, yy): mycontours.append((ix, iy)) self.contours = np.array(mycontours) except IOError: pass self.contour_area = self.calc_contour_area(self.contours) if not self.good_contour: print("######## No good contour found ########") self.contours = None self.contour_area = 0