def update_wcs(self, d): # d is a dictionary with xshift_best, yshift_best, astr_guess # for this EXTNAME assert (d['extname'] == self.header['EXTNAME']) wcs = d['astr_guess'] wcs.wcs.crpix = wcs.wcs.crpix + np.array( [d['xshift_best'], d['yshift_best']]) self.wcs = wcs # also want to update the header new_wcs_header_cards = wcs.to_header() new_wcs_header_cards['CONTRAST'] = d['contrast'] for k, v in new_wcs_header_cards.items(): if k == 'LATPOLE': continue self.header[k] = v self.header['CD1_1'] = self.header['PC1_1'] self.header['CD2_1'] = self.header['PC2_1'] self.header['CD1_2'] = self.header['PC1_2'] self.header['CD2_2'] = self.header['PC2_2'] del self.header['PC1_1'] del self.header['PC2_1'] del self.header['PC1_2'] del self.header['PC2_2']
def save_to_fits(img, fits_file, wcs=None, header=None, overwrite=True): """Save numpy 2-D arrays to `fits` file. (from `kungpao`) Parameters: img (np.array, 2d): The 2-D array to be saved fits_file (str): File name of `fits` file wcs (astropy.wcs.WCS class): World coordinate system of this image header (astropy.io.fits.header or str): header of this image overwrite (bool): Default is True Returns: None """ if wcs is not None: wcs_header = wcs.to_header() img_hdu = fits.PrimaryHDU(img, header=wcs_header) else: img_hdu = fits.PrimaryHDU(img) if header is not None: img_hdu.header = header if os.path.islink(fits_file): os.unlink(fits_file) img_hdu.writeto(fits_file, overwrite=overwrite) return
def __init__(self,data,wcs): if data.ndim == 3: data = np.sum(copy.deepcopy(data),axis=2) wcs = pywcs.WCS(wcs.to_header(),naxis=[1,2]) else: data = copy.deepcopy(data) self._data = data self._wcs = wcs
def wcs2hdrdict(wcs, hdr_defaults={}): """ Convert astropy.wcs object into a fits header dictionary Note: wcs.to_header method annoyingly removes cd_matrix and reset cdelt attributes, which is why this functions exists """ import collections hdr = collections.OrderedDict() hdr['WCSAXES'] = (2, 'Number of World Coordinate System axes') hdr['CRPIX1'] = 'Reference pixel for NAXIS1' hdr['CRPIX2'] = 'Reference pixel for NAXIS2' hdr['CRVAL1'] = '[deg] Coordinate value at reference point' hdr['CRVAL2'] = '[deg] Coordinate value at reference point' hdr['CTYPE1'] = 'Projection for NAXIS1' hdr['CTYPE2'] = 'Projection for NAXIS2' hdr['CUNIT1'] = 'Units of coordinate increment and value' hdr['CUNIT2'] = 'Units of coordinate increment and value' hdr['CROTA2'] = None hdr['CD1_1'] = 'Linear projection matrix element' hdr['CD1_2'] = 'Linear projection matrix element' hdr['CD2_1'] = 'Linear projection matrix element' hdr['CD2_2'] = 'Linear projection matrix element' hdr.update(hdr_defaults) wcs.to_header() for k in hdr.keys(): key = ''.join([ki for ki in k if not ki.isdigit()]).replace('_', '') idx = [int(i) - 1 for i in re.sub("\D", "", k)] if hasattr(wcs, key.lower()): prop = wcs.__getattribute__(key.lower()) if hasattr(prop, '__len__'): for i in idx: prop = prop[i] if isinstance(hdr[k], (tuple, list)) and len(hdr[k]) == 2: continue if isinstance(prop, (int, float)): hdr[k] = (prop, hdr[k]) else: hdr[k] = (str(prop), hdr[k]) return hdr
def make_coadd_map(maps,wcs,shape): header = wcs.to_header() data = np.zeros(shape) axes = wcs_to_axes(wcs,shape) for m in maps: c = wcs_to_coords(m.wcs,m.counts.shape) o = np.histogramdd(c.T,bins=axes[::-1],weights=np.ravel(m.counts))[0] data += o return Map(data,copy.deepcopy(wcs))
def toFitsHeader(self): """Convert to a FITS header Returns ------- header : `astropy.io.fits.Header` FITS header with WCS specifying wavelength array. """ wcs = astropy.wcs.WCS(naxis=1) wcs.wcs.ctype = ["WAVE"] wcs.wcs.cname = ["Wavelength"] wcs.wcs.crval = [0.5*(self.minWavelength + self.maxWavelength)] wcs.wcs.crpix = [0.5*len(self) + 1.5] # FITS is unit-indexed wcs.wcs.cunit = [astropy.units.nm] dWavelength = (self.maxWavelength - self.minWavelength)/(len(self) - 1) wcs.wcs.cdelt = [dWavelength] return wcs.to_header()
def build_meta(wcs, exif_data): time = get_image_time(exif_data) wcs.wcs.dateobs = time.isoformat() header = MetaDict(dict(wcs.to_header())) header.update(get_meta_from_exif(exif_data)) dsun = sunpy.coordinates.sun.earth_distance(time.isoformat()) lat = header.get('LAT') * u.deg lon = header.get('LON') * u.deg solar_rotation_angle = get_solar_rotation_angle(lat, lon, time) header.update({'crota2': solar_rotation_angle.to('deg').value}) header.update({'dsun_obs': dsun.to('m').value}) hgln_obs = 0 * u.deg hglt_obs = sunpy.coordinates.sun.B0(time) header.update({'hgln_obs': hgln_obs.to('deg').value}) header.update({'hglt_obs': hglt_obs.to('deg').value}) header.update({'ctype1': 'HPLN-TAN'}) header.update({'ctype2': 'HPLT-TAN'}) header.update({'rsun': dsun.to('m').value}) header.update({'rsun_obs': np.arctan(sunpy.sun.constants.radius / dsun).to( 'arcsec').value}) return header
def create_frame(background=0, std=100, crpix=None, keys=None): size = (100, 100) # Update WCS header wcs = create_wcs(crpix) y, x = numpy.mgrid[:100, :100] data = numpy.random.normal(background, std, size) model = Gaussian2D(amplitude=30 * background, x_mean=wcs.wcs.crpix[0] - 3.5, y_mean=wcs.wcs.crpix[1] - 12.8, x_stddev=3.0, y_stddev=4.0) data += model(x, y) hdu = fits.PrimaryHDU(data) hdu.header = wcs.to_header() if keys: for k, v in keys.items(): hdu.header[k] = v return fits.HDUList([hdu])
def create_frame(background=0, std=100, crpix=None, keys=None): size = (100, 100) # Update WCS header wcs = create_wcs(crpix) y, x = numpy.mgrid[:100, :100] data = numpy.random.normal(background, std, size) model = Gaussian2D( amplitude=30*background, x_mean=wcs.wcs.crpix[0]-3.5, y_mean=wcs.wcs.crpix[1]-12.8, x_stddev=3.0, y_stddev=4.0 ) data += model(x, y) hdu = fits.PrimaryHDU(data) hdu.header = wcs.to_header() if keys: for k, v in keys.items(): hdu.header[k] = v return fits.HDUList([hdu])
def _args_to_payload(self, **kwargs): # Convert arguments to a valid requests payload # Build the payload payload = {} # If a wcs is still present in the kwargs it means # the user called query_with_wcs if kwargs.get('wcs'): wcs = kwargs.pop('wcs') header = wcs.to_header() # hips2fits needs the size of the output image if wcs.pixel_shape is not None: nx, ny = wcs.pixel_shape header['NAXIS1'] = nx header['NAXIS2'] = ny else: # The wcs does not contain the size of the image raise AttributeError("""The WCS passed does not contain the size of the pixel image. Please add it to the WCS or refer to the query method.""") # Add the WCS to the payload header_json = dict(header.items()) header_str = json.dumps(header_json) payload.update({'wcs': header_str}) else: # The user called query payload.update({ 'width': kwargs.pop("width"), 'height': kwargs.pop("height"), 'projection': kwargs.pop("projection"), 'coordsys': kwargs.pop("coordsys"), 'rotation_angle': kwargs.pop("rotation_angle").to_value(u.deg), 'ra': kwargs.pop("ra").to_value(u.deg), 'dec': kwargs.pop("dec").to_value(u.deg), 'fov': kwargs.pop("fov").to_value(u.deg), }) # Min-cut min_cut_value = kwargs.pop('min_cut') min_cut_kw = str(min_cut_value) + '%' payload.update({'min_cut': min_cut_kw}) # Max-cut max_cut_value = kwargs.pop('max_cut') max_cut_kw = str(max_cut_value) + '%' payload.update({'max_cut': max_cut_kw}) # Colormap cmap = kwargs.pop('cmap') from matplotlib.colors import Colormap if isinstance(cmap, Colormap): cmap = cmap.name payload.update({'cmap': cmap}) # Stretch stretch = kwargs.pop('stretch') # TODO remove that: it must be handled properly by the server side # that should return a json error if stretch not in ('power', 'linear', 'sqrt', 'log', 'asinh'): msg = "stretch: must either 'power', 'linear', 'sqrt', 'log' or 'asinh'.\n" msg += str(stretch) + ' is ignored.' warnings.warn(msg, AstropyUserWarning) else: payload.update({'stretch': stretch}) payload.update({'stretch': stretch}) # HiPS hips = kwargs.pop("hips") # Output format format = kwargs.pop("format") payload.update({ "hips": hips, "format": format, }) # Check that all the arguments have been handled assert kwargs == {} return payload
def make_maps(coords: SkyCoord, ext: ExtinctionCatalogue, wcs: astropy.wcs.WCS, kde: KDE, n_iters: int = 3, tolerance: float = 3.0, use_xnicest: bool = True): """Map making algorithm. Parameters ---------- coords : SkyCoord The coordinates of all objects. Not all objects might have measured extinctions, so the size of this catalogue is generally larger than the one of `ext`. ext : ExtinctionCatalogue An extinction catalogue for the valid objects. Note that we use the `idx` attribute of the catalogue to select only valid objects in the coords. wcs : WCS A Worlk Coordinate System structure, returned for example by `guess_wcs`. kde : KDE A KDE object, the kernel density estimator that will be used to build smooth maps. n_iters : int, default to 3 The number of iterations performed. At the end of each iteration, unusual objects are clipped. Clipping does not occur if n_iters = 1. tolerance : float, default to 3.0 The maximum tolerance allowed in the extinction of each object. Objects that have an extinction that differs the local extinction by more than `tolerance` times the local standard deviation will be excluded from the analysis. This requires several passes or iterations, as dictated by the `n_iters` argument. use_xnicest : bool, default to True If False, the XNicest algorithm will not be used, not even if the `ext` catalogue has XNicest weights computed. Returns ------- fits.HDU A full HDU fits structure, which can be used directly to save a FITS file. Alternatively, one can use the `data` attribute of the result to obtain directly the various maps created. The `data` attribute is a 3D array: each "plane" contains different results: data[0] The XNicer extinction map, in units of [mag]. data[1] The inverse variance on the XNicer extinction map [mag^-2]. One can obtains the error of the extinction map by computing data[1]**(-0.5) data[2] The sum of weights of the extinction map [mag^-2 pix^-1]. This is mostly provided for sanity checks: pixels with a small value in data[2] indicate places where few objects are observed, or places where objects have large extinction measurement errors. data[3] The local density of objects, in units of [objects pix^-1]. data[4] The XNicest extinction map [mag]. Only returned if the XNicest algorithm has been used. data[5] The inverse variance on the XNicest extinction map [mag^-2]. Only returned if the XNicest algorithm has been used. data[6] The sum of weights of the XNIcest extinction map [mag^-2 pix^-1]. Only returned if the XNicest algorithm has been used. """ names = list(coords.frame.representation_component_names.keys()) if 'idx' in ext.colnames: xy = wcs.all_world2pix( getattr(coords, names[0]).deg[ext['idx']], getattr(coords, names[1]).deg[ext['idx']], 0) else: xy = wcs.all_world2pix( getattr(coords, names[0]).deg, getattr(coords, names[1]).deg, 0) xy = np.stack((xy[1], xy[0]), axis=-1) mask = kde.mask_inside(xy) n_objs = xy.shape[0] # Check if we need to use the XNicest algorithm xnicest = bool(use_xnicest) and ('xnicest_bias' in ext.colnames) # Weights & power arrays: 0-cmap, 1-cvar, 2-cwgt, 3-dmap # Moreover, if xnicest: 4-amap, 5-avar, 6-awgt if xnicest: weights = np.empty((7, n_objs)) power = np.zeros(7) else: weights = np.empty((4, n_objs)) power = np.zeros(4) ext_ivar = 1.0 / ext['variance_A'] weights[0, :] = ext['mean_A'] * ext_ivar weights[1, :] = ext['mean_A'] * ext['mean_A'] * ext_ivar weights[2, :] = ext_ivar weights[3, :] = 1 if xnicest: weights[4, :] = (ext['mean_A'] - ext['xnicest_bias']) * ext_ivar * \ ext['xnicest_weight'] # FIXME: The following line, used to compute the XNicest error, # ignores the error on the xnicest_weight. That is, the final error # will be computed by assuming only the error on the extinction. The # issue is not so easy to solve (one would need to take into account # both the variance on the XNicest weight and the covariance with the # extinction). For a further release... weights[5, :] = ext_ivar * ext['xnicest_weight'] power[5] = 1 weights[6, :] = ext_ivar * ext['xnicest_weight'] # Shifted (unframed) coordinates, to the nearest int x_ = np.rint(xy[:, 1] + kde.kernel_size).astype(np.int) y_ = np.rint(xy[:, 0] + kde.kernel_size).astype(np.int) for iteration in range(n_iters): if iteration < n_iters - 1: # Faster steps for intermediate iterations res = kde.kde(xy, weights[0:3], power=power[0:3], mask=mask, nocut=True) else: # Last iteration is complete; also, change the weights and power # for the map #1, so that it measures the expected variance, # instead of the observed one. weights[1] = weights[2] power[1] = 1 res = kde.kde(xy, weights, power=power, mask=mask, nocut=True) res[0] = np.divide(res[0], res[2], out=np.zeros_like(res[0]), where=(res[2] != 0)) if iteration < n_iters - 1: # Intermediate iterations: cvar is the observed scatter and has to # be computed as a sampled variance res[1] = np.divide(res[1], res[2], out=np.zeros_like(res[1]), where=(res[2] != 0)) res[1] -= res[0]**2 # Intermediate iterations: update the mask x_mask = x_[mask] y_mask = y_[mask] clip = (res[0, y_mask, x_mask] - ext['mean_A'][mask])** 2 \ > tolerance**2 * res[1, y_mask, x_mask] mask[np.where(mask)[0][clip]] = False else: # Last iteration: cvar is the ensemble variance res[1] = np.divide(res[2] * res[2], res[1], out=np.zeros_like(res[1]), where=(res[1] != 0)) if xnicest: # Last iteration: compute the other intermediate maps res[4] = np.divide(res[4], res[6], out=np.zeros_like(res[4]), where=(res[4] != 0)) res[5] = np.divide(res[6] * res[6], res[5], out=np.zeros_like(res[5]), where=(res[5] != 0)) # Cut the data res = res[:, kde.kernel_size:-kde.kernel_size, # type: ignore kde.kernel_size:-kde.kernel_size] # Prepare the header hdu = fits.PrimaryHDU(res, header=wcs.to_header()) hdu.header['PLANE1'] = ('extinction', '[mag]') hdu.header['PLANE2'] = ('inverse variance', '[mag^-2]') hdu.header['PLANE3'] = ('weight', '[mag^-2 pix^-1]') hdu.header['PLANE4'] = ('density', '[pix^-1], objects per pixel') if xnicest: hdu.header['PLANE5'] = ('extinction', '[mag], XNicest method') hdu.header['PLANE6'] = ('inverse variance', '[mag^-2], XNicest method') hdu.header['PLANE7'] = ('weight', '[mag^2 pix^-1], XNicest method') hdu.header['CREATOR'] = 'XNicer v0.2.0' hdu.header['DATE'] = datetime.datetime.now().isoformat() hdu.header['AUTHOR'] = 'Marco Lombardi' hdu.add_checksum() # All done: return the final maps, truncated return hdu
def write_fits_image(data,wcs,outfile): hdu_image = pyfits.PrimaryHDU(data,header=wcs.to_header()) # hdulist = pyfits.HDUList([hdu_image,h['GTI'],h['EBOUNDS']]) hdulist = pyfits.HDUList([hdu_image]) hdulist.writeto(outfile,clobber=True)
def macro(self, exposure: Exposure, context: Dict[str, Any] = {}): if exposure.wcs is None: wcs = astropy.wcs.WCS() else: wcs = exposure.wcs return list(wcs.to_header().cards)
def _dump_fits(filename, data, wcs, overwrite=False): fits.writeto( filename, data, header=wcs.to_header(), output_verify='exception', overwrite=overwrite, checksum=True)