def cone_search(self, ra, dec, radius):
        """
        Searches for sources in a cone of given radius and center

        :param ra: decimal degrees, R.A. of the center of the cone
        :param dec: decimal degrees, Dec. of the center of the cone
        :param radius: radius in degrees
        :return: a table with the list of sources
        """

        skycoord = SkyCoord(ra=ra * u.degree, dec=dec * u.degree, frame='icrs')

        # First check that we have an active internet connection
        if not internet_connection_is_active():  # pragma: no cover

            raise ConeSearchFailed("It looks like you don't have an active internet connection. Cannot continue.")

        with warnings.catch_warnings():
            
            #Ignore all warnings, which are many from the conesearch module
            
            warnings.simplefilter('ignore')
            
            try:
                
                votable = conesearch.conesearch(skycoord, radius, 
                                                catalog_db=self.catalog,
                                                verb=3, verbose=True,
                                                cache=False)
            
            except VOSError as exc:  # Pragma: no cover

                # Download failed

                raise ConeSearchFailed("Cone search failed. Reason: %s" % exc.message)

            else:

                # Download successful

                table = votable.to_table()

                self._last_query_results = table.to_pandas().set_index('name').sort_values("Search_Offset")

                out = self.apply_format(table)

                #This is needed to avoid strange errors
                del votable
                del table

                # Save coordinates of center of cone search
                self._ra = ra
                self._dec = dec

                # Make a DataFrame with the name of the source as index

                return out
Example #2
0
def main( ra, dec, radius, output=False ):
	"""
	important params:
	'RAJ2000','DEJ2000','B1mag','R1mag','B2mag','R2mag','Imag'
	"""
	if output != False:
		if os.path.exists(output) == True:
			t	= ascii.read(output)
			return t

	conf.conesearch_dbname = 'conesearch_warn'
	catalog 	= 'The USNO-B1.0 Catalog (Monet+ 2003) 1'
	c		= SkyCoord(ra=ra,dec=dec,unit="degree")
	t		= conesearch.conesearch(c, radius*u.degree, catalog_db=catalog).to_table()

	if len(t) == 0:
		print "No USNO-B1.0 Catalog (%s,%s,%s)" % (ra,dec,radius)
		return None

	name_ls	= ["B1mag","B2mag","R1mag","R2mag","Imag"]
	for name in name_ls:
		select		= np.ma.getmask(t[name])
		t[name][select] = np.nan
	
	t.rename_column('RAJ2000','RA')
	t.rename_column('DEJ2000','DEC')
	
	filt_ls	= ["B","R","I"]
	for filt in filt_ls:
		if filt in ["B","R"]:
			name1	= "%s1mag"%filt
			n1	= len(t[name1][~np.isnan(t[name1])])

			name2	= "%s2mag"%filt
			n2	= len(t[name2][~np.isnan(t[name2])])
			
			if filt == "R":filt="Rc"
				
			if n1 <= n2:
				t.rename_column(name2,'%sMAG'%filt)
			elif n2 < n1:
				t.rename_column(name1,'%sMAG'%filt)
		
		if filt == "I":
			t.rename_column("%smag"%filt,'%scMAG'%filt)

	if output != False:
		ascii.write(t,output)

	#print t
	return t
Example #3
0
def main(ra, dec, radius, output=False):
    """
	important params:
	'ra','dec','j_m','j_cmsig','j_msigcom','j_snr',h...,k....,'glon','glat'
	"""
    if output != False:
        if os.path.exists(output) == True:
            t = ascii.read(output)
            return t

    conf.conesearch_dbname = 'conesearch_good'
    catalog = 'Two Micron All Sky Survey (2MASS) 1'
    c = SkyCoord(ra=ra, dec=dec, unit="degree")
    t = conesearch.conesearch(c, radius * u.degree,
                              catalog_db=catalog).to_table()

    if len(t) == 0:
        print "No 2MASS Catalog (%s,%s,%s)" % (ra, dec, radius)
        return None

    t.rename_column('ra', 'RA')
    t.rename_column('dec', 'DEC')

    filt_ls = ["J", "H", "K"]
    for filt in filt_ls:
        if filt in ["J", "H"]:
            t.rename_column('%s_m' % filt.lower(), '%sMAG' % filt)
            t.rename_column('%s_cmsig' % filt.lower(), '%sMAGERR' % filt)

        elif filt == "K":
            t.rename_column('%s_m' % filt.lower(), '%ssMAG' % filt)
            t.rename_column('%s_cmsig' % filt.lower(), '%ssMAGERR' % filt)

    if output != False:
        ascii.write(t, output)

    #print t
    return t
Example #4
0
from astroquery.vo_conesearch.conesearch import conesearch
from astropy import units as u
from astropy.coordinates import SkyCoord
center = SkyCoord(189.1 * u.deg, 3 * u.deg, frame='galactic')
search = conesearch(
    center=center,
    radius=1,
    verb=1,
    catalog_db=
    "http://vizier.u-strasbg.fr/viz-bin/votable/-A?-source=IPHAS2&-out.all&")
search.to_table().write('../data/snrpic/iphas-data.fits',
                        format='fits',
                        overwrite=True)
Example #5
0
    def search(self, **params):
        """
        For compatibility with generic star catalog search.
        """

        self.logger.debug("search params=%s" % (str(params)))
        ra, dec = params['ra'], params['dec']
        if not (':' in ra):
            # Assume RA and DEC are in degrees
            ra_deg = float(ra)
            dec_deg = float(dec)
        else:
            # Assume RA and DEC are in standard string notation
            ra_deg = wcs.hmsStrToDeg(ra)
            dec_deg = wcs.dmsStrToDeg(dec)

        # Convert to degrees for search radius
        radius_deg = float(params['r']) / 60.0
        # radius_deg = float(params['r'])

        # Note requires astropy 0.3.x+
        c = coordinates.SkyCoord(ra_deg * units.degree,
                                 dec_deg * units.degree,
                                 frame='icrs')
        self.logger.info("Querying catalog: %s" % (self.full_name))
        time_start = time.time()
        with warnings.catch_warnings():  # Ignore VO warnings
            warnings.simplefilter('ignore')
            results = conesearch.conesearch(c,
                                            radius_deg * units.degree,
                                            catalog_db=self.full_name,
                                            verbose=False)
        time_elapsed = time.time() - time_start
        numsources = results.array.size
        self.logger.info("Found %d sources in %.2f sec" %
                         (numsources, time_elapsed))

        # Scan the returned fields to find ones we need to extract
        # particulars from (ra, dec, id, magnitude)
        mags = []
        ext = {}
        fields = results.array.dtype.names
        for name in fields:
            ucd = results.get_field_by_id(name).ucd
            ucd = str(ucd).lower()
            if ucd == 'id_main':
                ext['id'] = name
            elif ucd == 'pos_eq_ra_main':
                ext['ra'] = name
            elif ucd == 'pos_eq_dec_main':
                ext['dec'] = name
            if ('phot_' in ucd) or ('phot.' in ucd):
                mags.append(name)
        self.logger.debug("possible magnitude fields: %s" % str(mags))
        if len(mags) > 0:
            magfield = mags[0]
        else:
            magfield = None

        # prepare the result list
        starlist = []
        arr = results.array
        for i in range(numsources):
            source = dict(zip(fields, arr[i]))
            starlist.append(self.toStar(source, ext, magfield))

        # metadata about the list
        columns = [
            ('Name', 'name'),
            ('RA', 'ra'),
            ('DEC', 'dec'),
            ('Mag', 'mag'),
            ('Preference', 'preference'),
            ('Priority', 'priority'),
            ('Description', 'description'),
        ]
        # Append extra columns returned by search to table header
        # TODO: what if not all sources have same record structure?
        # is this possible with VO?
        cols = list(fields)
        cols.remove(ext['ra'])
        cols.remove(ext['dec'])
        cols.remove(ext['id'])
        columns.extend(zip(cols, cols))

        # which column is the likely one to color source circles
        colorCode = 'Mag'

        info = Bunch.Bunch(columns=columns, color=colorCode)
        return starlist, info
    def cone_search(self, ra, dec, radius):
        """
        Searches for sources in a cone of given radius and center

        :param ra: decimal degrees, R.A. of the center of the cone
        :param dec: decimal degrees, Dec. of the center of the cone
        :param radius: radius in degrees
        :return: a table with the list of sources
        """

        skycoord = SkyCoord(ra=ra * u.degree, dec=dec * u.degree, frame="icrs")

        # First check that we have an active internet connection
        if not internet_connection_is_active():  # pragma: no cover

            raise ConeSearchFailed(
                "It looks like you don't have an active internet connection. Cannot continue."
            )

        with warnings.catch_warnings():

            # Ignore all warnings, which are many from the conesearch module

            warnings.simplefilter("ignore")

            try:

                votable = conesearch.conesearch(
                    skycoord,
                    radius,
                    catalog_db=self.catalog,
                    verb=3,
                    verbose=True,
                    cache=False,
                )

            except VOSError as exc:  # Pragma: no cover

                # Download failed

                raise ConeSearchFailed("Cone search failed. Reason: %s" %
                                       exc.message)

            else:

                # Download successful
                table = votable
                # Workaround to comply with newer versions of astroquery
                if isinstance(votable, astropy.io.votable.tree.Table):
                    table = votable.to_table()

                if table is None:

                    log.error("Your search returned nothing")

                    return None

                table.convert_bytestring_to_unicode()

                pandas_df = (table.to_pandas().set_index("name").sort_values(
                    "Search_Offset"))

                str_df = pandas_df.select_dtypes([object])

                if astropy_old:
                    str_df = str_df.stack().str.decode("utf-8").unstack()

                for col in str_df:
                    pandas_df[col] = str_df[col]

                if astropy_old:
                    new_index = [x.decode("utf-8") for x in pandas_df.index]
                    pandas_df.index = new_index

                self._last_query_results = pandas_df

                out = self.apply_format(table)

                # This is needed to avoid strange errors
                del votable
                del table

                # Save coordinates of center of cone search
                self._ra = ra
                self._dec = dec

                # Make a DataFrame with the name of the source as index

                return out
try:
    lun = open(file_stars_pkl, 'rb')
    cat = pickle.load(lun)
    lun.close()
    print("Loaded: " + file_stars_pkl)
    
except FileNotFoundError:
    
    name_cat = u'Guide Star Catalog v2 1'
    #            name_cat = u'The HST Guide Star Catalog, Version 1.1 (Lasker+ 1992) 1' # works, but 1' errors; investigating
    
    #            stars = conesearch.conesearch(w.wcs.crval, 0.3, cache=False, catalog_db = name_cat)
    
    with data.conf.set_temp('remote_timeout', 200): # This is the very strange syntax to set a timeout delay.
                                               # The default is 3 seconds, and that times out often.
        stars = conesearch.conesearch(w.wcs.crval, radius, cache=False, catalog_db = name_cat)
    
    # Extract proper fields
       
    ra_cat  = np.array(stars.array['ra'])*hbt.d2r # Convert to radians
    dec_cat = np.array(stars.array['dec'])*hbt.d2r # Convert to radians
    mag_cat       = np.array(stars.array['Mag'])
    
    # Sort the stars. I don't know why stars.sort('mag') doesn't work, but it fails.
    
    order = np.argsort(mag_cat)
    
    ra_cat = ra_cat[order]
    dec_cat = dec_cat[order]
    mag_cat = mag_cat[order]
    
def get_fits_table_from_server(catalog, server, ra, dec, sr, verbose=False):
    """
    This function fetches sources from the specified catalog from the specified
    server within the search radius and returns a Table containing them.

    Parameters
    ----------
    catalog : {'sdss9', '2mass', 'ukidss9', 'gmos'}
        Name of catalog to search.
    server : str
        Name of server to query [sdss9_mko | sdss9_cpo | sdss9_vizier |
        2mass_mko | 2mass_cpo | 2mass_vizier | ukidss9_mko | ukidss9_cpo]
    ra : float
        Right ascension of search center, decimal degrees.
    dec : float
        Declination of search center, decimal degrees.
    sr : float
        Search radius, decimal degrees.
    verbose : bool
        Verbose output.

    Returns
    -------
    `astropy.table.Table`
        Sources within the search cone.

    """
    # OK, do the query
    url = SERVER_URLS[server]
    cols = CAT_COLS[catalog]
    server_cols = SERVER_COLMAP[server]

    if verbose:
        print("RA, Dec, radius :", ra, dec, sr)
        print("catalog         :", catalog)
        print("server          :", server)
        print("url             :", url)
        print("cols            :", cols)
        print("server_cols     :", server_cols)
        print("\n\n")

    # turn on verbose for debug to stdout.
    # Need verb=3 to get the right cols from vizier

    # astroquery 0.4 removed the pedantic keyword in favor of the config
    # item, and switched to returning an astropy table by default (hence
    # return_astropy_table=False below).
    # Another change is that conesearch returns None and issue of
    # NoResultsWarning if no results are found, instead of raising a
    # VOSError: https://github.com/astropy/astroquery/pull/1528
    try:
        try:
            table = conesearch((ra, dec),
                               sr,
                               verb=3,
                               catalog_db=url,
                               return_astropy_table=False,
                               verbose=False)
        except TypeError:
            # astroquery < 0.4
            table = conesearch((ra, dec),
                               sr,
                               verb=3,
                               catalog_db=url,
                               pedantic=False,
                               verbose=False)
    except VOSError:
        log.stdinfo("VO conesearch produced no results")
        return

    # Did we get any results?
    if table is None or table.is_empty() or len(table.array) == 0:
        log.stdinfo(f"No results returned from {server}")
        return

    array = table.array

    if server == 'sdss9_vizier':
        # Vizier uses the photoObj table from SDSS9, whereas the internal
        # server uses the calibObj, AKA "datasweep", which contains a subset
        # of photoObj, "designed for those who want to work with essentially
        # every well measured object, but only need the most commonly used
        # parameters".
        #
        # To get results similar to calibObj, we filter below on mode=1 to get
        # only the primary sources (the 'main' photometric observation of an
        # object). calibObj also uses a cut on magnitudes (see
        # http://www.sdss3.org/dr9/imaging/catalogs.php) but this is difficult
        # to reproduce here since the cuts apply to extinction-corrected
        # magnitudes, and we don't have the extinction values in the Vizier
        # table.
        array = array[array['mode'] == 1]

    # It turns out to be not viable to use UCDs to select the columns,
    # even for the id, ra, and dec. Even with vizier. <sigh>
    # The first column is our running integer column
    ret_table = Table([list(range(1,
                                  len(array) + 1))],
                      names=('Id', ),
                      dtype=('i4', ))

    ret_table.add_column(
        Column(array[server_cols[0]], name='Cat_Id', dtype='a'))
    ret_table.add_column(
        Column(array[server_cols[1]], name='RAJ2000', dtype='f8', unit='deg'))
    ret_table.add_column(
        Column(array[server_cols[2]], name='DEJ2000', dtype='f8', unit='deg'))

    # Now the photometry columns
    for col in range(3, len(cols)):
        ret_table.add_column(
            Column(array[server_cols[col]],
                   name=cols[col],
                   dtype='f4',
                   unit='mag',
                   format='8.4f'))

    header = add_header_to_table(ret_table)
    header['CATALOG'] = (catalog.upper(), 'Origin of source catalog')

    # Add comments to the header to describe it
    header.add_comment(f'Source catalog derived from the {catalog} catalog')
    header.add_comment(f'Source catalog fetched from server at {url}')
    header.add_comment(f'Delivered Table name from server:  {table.name}')
    for col in range(len(cols)):
        header.add_comment('UCD for field {} is {}'.format(
            cols[col],
            table.get_field_by_id(server_cols[col]).ucd))
    return ret_table
def nh_jring_create_objectlist(file_in, do_stars=True, bodies = [], num_stars_max = 100):
    
    ''' 
    Creates a text file which lists all the stars in a file, with lines like
    
        'star', <xpos>, <ypos>, mag [optional]

    <xpos> and <ypos> are the x and y coordinate centers, in pixels.
    The output is sorted by magnitude, if it is available. 
    
    <bodies> is a list, like ['Adrastea', 'Amalthea'], etc.
    
    It is OK to have xpos and ypos be outside the screen. We might want to know that sometimes, for satellites.
    '''

#    file_in    = 'lor_0034962025_0x630_sci_1_opnav.fit'
    dir_images = '/Users/throop/data/NH_Jring/data/jupiter/level2/lor/all/'
    dir_out    = '/Users/throop/data/NH_Jring/out/'
    
    file_in_base = file_in.split('/')[-1]   # Strip the pathname
    file_out_base = file_in_base.replace('.fit', '_objects.txt')
    file_out   = dir_out + file_out_base

# If we were passed a

    file = dir_images + file_in_base
   
    header = hbt.get_image_header(dir_images + file_in_base)

    dx_pix = header['NAXIS1']
    dy_pix = header['NAXIS2']
    
    radius_search = 0.2 * u.deg
    
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        w = WCS(file)
        
    name_cat = u'Guide Star Catalog v2 1'# Works on gobi only (no tomato laptop)
    name_cat = 'The HST Guide Star Catalog, Version GSC-ACT (Lasker+ 1996-99) 1'
    url_cat = 'http://gsss.stsci.edu/webservices/vo/ConeSearch.aspx?CAT=GSC23&' # Works always

    with data.conf.set_temp('remote_timeout', 30): # This is the very strange syntax to set a timeout delay.
                                                   # The default is 3 seconds, and that times out often.
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            pos = (w.wcs.crval[0], w.wcs.crval[1])  # Get errors about invalid coords. Convert from np arr → tuple, ugh.
            stars = conesearch.conesearch(pos, radius_search, cache=True, catalog_db = url_cat)

    # NB: the returned value is a Table, but I have to access via .array[] -- not sure why.
    
    ra_stars  = np.array(stars.array['ra'])*hbt.d2r # Convert to radians
    dec_stars = np.array(stars.array['dec'])*hbt.d2r # Convert to radians

    mag_stars = np.array(stars.array['Mag'])
    
    print("Stars downloaded: {}; mag = {} .. {}".format(np.size(mag_stars), np.nanmin(mag_stars), np.nanmax(mag_stars)))
    print("RA = {} .. {}".format(np.nanmin(ra_stars)*hbt.r2d, np.nanmax(ra_stars)*hbt.r2d))
    
    # Now sort by magnitude, and keep the 100 brightest

    order = np.argsort(mag_stars)
    order = np.array(order)[0:num_stars_max]

    ra_stars        = ra_stars[order]
    dec_stars       = dec_stars[order]
    mag_stars       = mag_stars[order]
    
    radec_stars        = np.transpose(np.array((ra_stars,dec_stars)))
    x_stars, y_stars   = w.wcs_world2pix(radec_stars[:,0]*hbt.r2d, radec_stars[:,1]*hbt.r2d, 0)
  
    is_good = np.logical_and( np.logical_and(x_stars >=0, x_stars <= dx_pix),
                              np.logical_and(y_stars >=0, y_stars <= dy_pix) )
    
# Now make a table
    
    t_stars          = Table()
    t_stars['name']  = np.zeros(np.shape(mag_stars[is_good]), dtype='U30')
    t_stars['name'][:] = u'star'    

    t_stars['x_pix'] = x_stars[is_good]
    t_stars['y_pix'] = y_stars[is_good]
    t_stars['mag']   = mag_stars[is_good]


#==============================================================================
# Now find the satellite locations
#==============================================================================

    if np.size(bodies) > 0:
        
# Look up satellite positions

        et = header['SPCSCET']
        utc = sp.et2utc(et, 'C', 0)
        x_bodies, y_bodies = hbt.get_pos_bodies(et, bodies, units='pixels', wcs=w)
        t_sats = Table()
        t_sats['x_pix'] = x_bodies
        t_sats['y_pix'] = y_bodies
        t_sats['name']  = np.array(bodies).astype('U30')

#==============================================================================
# Merge the stars and sats into one table
#==============================================================================
                 
        t_merged = vstack([t_stars, t_sats])

    else:
        t_merged = t_stars
              
#==============================================================================
# And write the table to disk
#==============================================================================

    t_merged.write(file_out, format = 'csv', overwrite = True)
    print("Wrote: {} ({} objects)".format(file_out, np.shape(t_merged)[0]))
#    
    return t_merged
Example #10
0
    def cone_search(self, ra, dec, radius):
        """
        Searches for sources in a cone of given radius and center

        :param ra: decimal degrees, R.A. of the center of the cone
        :param dec: decimal degrees, Dec. of the center of the cone
        :param radius: radius in degrees
        :return: a table with the list of sources
        """

        skycoord = SkyCoord(ra=ra * u.degree, dec=dec * u.degree, frame='icrs')

        # First check that we have an active internet connection
        if not internet_connection_is_active():  # pragma: no cover

            raise ConeSearchFailed(
                "It looks like you don't have an active internet connection. Cannot continue."
            )

        with warnings.catch_warnings():

            #Ignore all warnings, which are many from the conesearch module

            warnings.simplefilter('ignore')

            try:

                votable = conesearch.conesearch(skycoord,
                                                radius,
                                                catalog_db=self.catalog,
                                                verb=3,
                                                verbose=True,
                                                cache=False)

            except VOSError as exc:  # Pragma: no cover

                # Download failed

                raise ConeSearchFailed("Cone search failed. Reason: %s" %
                                       exc.message)

            else:

                # Download successful

                table = votable.to_table()

                self._last_query_results = table.to_pandas().set_index(
                    'name').sort_values("Search_Offset")

                out = self.apply_format(table)

                #This is needed to avoid strange errors
                del votable
                del table

                # Save coordinates of center of cone search
                self._ra = ra
                self._dec = dec

                # Make a DataFrame with the name of the source as index

                return out
Example #11
0
    def search(self, **params):
        """
        For compatibility with generic star catalog search.
        """

        self.logger.debug("search params=%s" % (str(params)))
        ra, dec = params['ra'], params['dec']
        if not (':' in ra):
            # Assume RA and DEC are in degrees
            ra_deg = float(ra)
            dec_deg = float(dec)
        else:
            # Assume RA and DEC are in standard string notation
            ra_deg = wcs.hmsStrToDeg(ra)
            dec_deg = wcs.dmsStrToDeg(dec)

        # Convert to degrees for search radius
        radius_deg = float(params['r']) / 60.0
        # radius_deg = float(params['r'])

        # Note requires astropy 0.3.x+
        c = coordinates.SkyCoord(ra_deg * units.degree,
                                 dec_deg * units.degree,
                                 frame='icrs')
        self.logger.info("Querying catalog: %s" % (self.full_name))
        time_start = time.time()
        with warnings.catch_warnings():  # Ignore VO warnings
            warnings.simplefilter('ignore')
            results = conesearch.conesearch(
                c, radius_deg * units.degree, catalog_db=self.full_name,
                verbose=False)
        time_elapsed = time.time() - time_start
        numsources = results.array.size
        self.logger.info("Found %d sources in %.2f sec" % (
            numsources, time_elapsed))

        # Scan the returned fields to find ones we need to extract
        # particulars from (ra, dec, id, magnitude)
        mags = []
        ext = {}
        fields = results.array.dtype.names
        for name in fields:
            ucd = results.get_field_by_id(name).ucd
            ucd = str(ucd).lower()
            if ucd == 'id_main':
                ext['id'] = name
            elif ucd == 'pos_eq_ra_main':
                ext['ra'] = name
            elif ucd == 'pos_eq_dec_main':
                ext['dec'] = name
            if ('phot_' in ucd) or ('phot.' in ucd):
                mags.append(name)
        self.logger.debug("possible magnitude fields: %s" % str(mags))
        if len(mags) > 0:
            magfield = mags[0]
        else:
            magfield = None

        # prepare the result list
        starlist = []
        arr = results.array
        for i in range(numsources):
            source = dict(zip(fields, arr[i]))
            starlist.append(self.toStar(source, ext, magfield))

        # metadata about the list
        columns = [('Name', 'name'),
                   ('RA', 'ra'),
                   ('DEC', 'dec'),
                   ('Mag', 'mag'),
                   ('Preference', 'preference'),
                   ('Priority', 'priority'),
                   ('Description', 'description'),
                   ]
        # Append extra columns returned by search to table header
        # TODO: what if not all sources have same record structure?
        # is this possible with VO?
        cols = list(fields)
        cols.remove(ext['ra'])
        cols.remove(ext['dec'])
        cols.remove(ext['id'])
        columns.extend(zip(cols, cols))

        # which column is the likely one to color source circles
        colorCode = 'Mag'

        info = Bunch.Bunch(columns=columns, color=colorCode)
        return starlist, info
Example #12
0
# Set up matplotlib
import matplotlib.pyplot as plt

import streamlit as st

st.title('Conesearch Examples')
sbar_text = 'This page uses the `astroquery.vo_conesearch` package '
sbar_text += 'and borrows heavily from an astropy-tutorials demo.'
st.sidebar.markdown(sbar_text)

# options = {'angular diameter': angular_diameter,
#             'lookback time: Matplotlib':lookback_mpl,
#             'lookback time: Altair': lookback_altair,
#             'lookback time: Bokeh': lookback_bokeh,
#             'lookback time: Plotly': lookback_plotly,
#             }
# to_plot = st.sidebar.radio("Type of plot", list(options.keys()), 0)

st.markdown('## Catalogs available')
st.write(conesearch.list_catalogs())

target = st.sidebar.text_input('Astronomical object:', value='m31')
st.markdown('## Target object')
st.markdown(target)
c = coord.SkyCoord.from_name(target, frame='icrs')
st.write(c)

result = conesearch.conesearch(c, 0.1 * u.degree)
st.markdown(f'First non-empty table returned by {result.url}')
st.markdown(f'Number of rows is {result.nrows}')
plt.imshow(stretch(image))

# Load matching stars

DO_GSC1     = False    # Stopped working 2-Oct-2016
DO_GSC2     = True
DO_USNOA2   = False

#==============================================================================
# Get stars from star catalogs     
#==============================================================================

if (DO_GSC1):
    name_cat = u'The HST Guide Star Catalog, Version 1.1 (Lasker+ 1992) 1' # works, but 1' errors; investigating
    stars = conesearch.conesearch(w.wcs.crval, radius_search, cache=False, catalog_db = name_cat)
    ra_stars  = np.array(stars.array['RAJ2000'])*d2r # Convert to radians
    dec_stars = np.array(stars.array['DEJ2000'])*d2r # Convert to radians
#            table_stars = Table(stars.array.data)

if (DO_GSC2):
    name_cat = u'Guide Star Catalog v2 1'
    file_pickle = dir_out + file_short.replace('.fit', '') + '.stars_gsc.pkl'

#    # If there is already a saved pickle file, then load from disk
#    
#    if os.path.isfile(file_pickle):
#        
#        print("Loading file: " + file_pickle)
#        lun = open(file_pickle, 'rb')
#        (ra_stars, dec_stars) = pickle.load(lun)
def navigate_image_stellar(im, wcs_in, name_catalog='', do_plot=True, method='fft', title=''):

    """
    Navigate frame based on stellar images.
    Result returns is pixel shift (dy, dx).
    WCS paramaters are returned, *and* modified in place.
    """
    
    import imreg_dft as ird
    from   astropy.wcs import WCS
    
    # from   astropy.vo.client import conesearch # Virtual Observatory, ie star catalogs   # DEPRECATED!
    from   astroquery.vo_conesearch import conesearch                 # New home of conesearch
    
# Inputs are the image array, and the WCS structure.
# This routine does not do any file IO. The image array and header must be already loaded.
# The image is assumed to be stretched properly s.t. stars can be found using DAOphot. 

    NUM_STARS_PHOT = 100  # How many stars to use from DAOPhot. For noisy images, DAO will find a lot of
                          # fake stars, so we need to crank this up higher than the # of cat stars.
    NUM_STARS_CAT  = 50  # How many stars to use from star catalog

    DO_GSC1     = False
    DO_GSC12     = True
    DO_USNOA2   = False
    
#==============================================================================
# Calculate the image radius, in radians, based on the size and the pixel scale
#==============================================================================

    dx_pix = hbt.sizex(im)
    dy_pix = hbt.sizey(im)
    radec_corner = wcs_in.wcs_pix2world(0, dy_pix/2, 0)
    radec_center = wcs_in.wcs_pix2world(dx_pix/2, dy_pix/2, 0)
    (ra_corner, dec_corner) = radec_corner
    (ra_center, dec_center) = radec_center
    
    radius_image = math.sqrt((dec_corner-dec_center)**2 + 
                             ((ra_corner-ra_center) / np.cos(dec_corner*hbt.d2r))**2) * hbt.d2r

    radius_search_deg = radius_image * hbt.r2d
    
# Read the WCS coordinates
           
    center_deg  = wcs_in.wcs.crval  # degrees. # crval is a two-element array of [RA, Dec], in degrees

# Stretch the image. This is just for display -- no processing.

    stretch_percent = 90
    stretch = astropy.visualization.PercentileInterval(stretch_percent)  # PI(90) scales array to 5th .. 95th %ile. 

# Display it

    if (do_plot):
        plt.imshow(stretch(im))

#==============================================================================
# Get stars from star catalogs     
#==============================================================================
    
    if (DO_GSC1):
        name_cat = u'The HST Guide Star Catalog, Version 1.1 (Lasker+ 1992) 1' # works, but 1' errors; investigating
        stars = conesearch.conesearch(center_deg, radius_search_deg, cache=True, catalog_db = name_cat)
        ra_stars  = np.array(stars.array['RAJ2000'])*hbt.d2r # Convert to radians
        dec_stars = np.array(stars.array['DEJ2000'])*hbt.d2r # Convert to radians
    #            table_stars = Table(stars.array.data)
    
    if (DO_GSC12):
#        name_cat = u'The HST Guide Star Catalog, Version 1.2 (Lasker+ 1996) 1'
        name_cat = u'Guide Star Catalog v2 1'                                       # Works from gobi, not tomato
        url_cat = 'http://gsss.stsci.edu/webservices/vo/ConeSearch.aspx?CAT=GSC23&' # Works always
            
        with data.conf.set_temp('remote_timeout', 30): # This is the very strange syntax to set a timeout delay.
                                                       # The default is 3 seconds, and that times out often.
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")                                                          
                # stars = conesearch.conesearch(wcs_in.wcs.crval, radius_search_deg, cache=True, catalog_db = url_cat)

                # The various functions of conesearch/ConeSearch/etc are quite confusing, and are in flux.                
                # This line below seems to work. It does not allow an explicit catalog suggstion, but it does the job.
                
                c = astropy.coordinates.SkyCoord(wcs_in.wcs.crval[0], wcs_in.wcs.crval[1], unit='deg')
                stars = ConeSearch.query_region(c, f'{radius_search_deg} deg')
    
        ra_stars  = np.array(stars.array['ra'])*hbt.d2r  # Convert to radians
        dec_stars = np.array(stars.array['dec'])*hbt.d2r # Convert to radians
    
        mag       = np.array(stars.array['Mag'])
        
        print("Stars downloaded: N = {}; mag = {:.2f} .. {:.2f}".format(np.size(mag), np.nanmin(mag), np.nanmax(mag)))
        print("RA = {:.2f} .. {:.2f}".format(np.nanmin(ra_stars)*hbt.r2d, np.nanmax(ra_stars)*hbt.r2d))
        
        # Now sort by magnitude, and keep the 100 brightest
        # This is because this GSC catalog is huge -- typically 2000 stars in LORRI FOV.
        # We need to reduce its size to fit in our fixed astropy table string length.
    
        order = np.argsort(mag)
        order = np.array(order)[0:NUM_STARS_CAT]
    
        ra_stars = ra_stars[order]   # Returned as radians
        dec_stars = dec_stars[order]
    
    if (DO_USNOA2):  
        name_cat = u'The USNO-A2.0 Catalogue (Monet+ 1998) 1' # Works but gives stars down to v=17; I want to v=13 
        stars = conesearch.conesearch(wcs_in.wcs.crval, 0.3, cache=False, catalog_db = name_cat)
        table_stars = Table(stars.array.data)
        mask = table_stars['Bmag'] < 13
        table_stars_m = table_stars[mask]            
    
        ra_stars  = table_stars_m['RAJ2000']*hbt.d2r # Convert to radians
        dec_stars = table_stars_m['DEJ2000']*hbt.d2r # Convert to radians
    
    ra_stars_cat  = ra_stars
    dec_stars_cat = dec_stars

    radec_stars_cat        = np.transpose(np.array((ra_stars_cat, dec_stars_cat)))
    
    (x_stars_cat, y_stars_cat) = wcs_in.wcs_world2pix(
                                                      radec_stars_cat[:,0]*hbt.r2d, 
                                                      radec_stars_cat[:,1]*hbt.r2d, 0)   
    
    points_stars_cat = np.transpose((y_stars_cat, x_stars_cat))  # Yes, order is supposed to be (y,x)

#==============================================================================
# Use DAOphot to search the image for stars.
#==============================================================================
  
    points_stars_phot = hbt.find_stars(im, num=NUM_STARS_PHOT) # Returns N x 2 aray. 0 = Row = y; 1 = Column = x.
    
    y_stars_phot =(points_stars_phot[:,0]) # xy is correct -- see above
    x_stars_phot =(points_stars_phot[:,1]) # 

#==============================================================================
# Make a plot showing the DAO stars on the image
#==============================================================================

    color_phot = 'red'            # Color for stars found photometrically
    color_cat  = 'lightgreen'     # Color for stars in catalog
    
    DO_PLOT_DAO = False   # Plot an intermediate result?
    
    if (DO_PLOT_DAO):

        plt.imshow(stretch(im))

        plt.plot(x_stars_phot, y_stars_phot, linestyle='none', 
                 marker='o', markersize=9, mec=color_cat, mew=1, color='none', 
                 label = 'DAO photometric stars') # plot() uses x, y

        plt.plot(x_stars_cat, y_stars_cat, linestyle='none', 
                 marker='o', markersize=5, color='lightgreen', 
                 label = 'Cat stars') # plot() uses x, y        

        plt.title(title)
        plt.ylim((hbt.sizey(im)),0)
        plt.xlim((0,hbt.sizex(im)))
        plt.legend(loc = 'upper left')
        plt.show()

# Up til here, x and y are correct
    
#==============================================================================
# Look up the shift between the photometry and the star catalog. 
# Do this by making a pair of fake images, and then looking up image registration on them.
#==============================================================================

# I call this pointing process 'opnav'. 
# It is returned in order (y,x) because that is what imreg_dft uses, even though it is a bit weird.
    
    diam_kernel = 11  # How many pixels across are our synthetic stellar images? Should be odd number. Not critical.
    do_binary = True  # For the stellar images, do a binary 1/0 (recommended), or a pixel distance?

    shape = np.shape(im)   # Set shape of output array
    
    image_cat  = hbt.image_from_list_points(points_stars_cat,  shape, diam_kernel, do_binary=do_binary)
    image_phot = hbt.image_from_list_points(points_stars_phot, shape, diam_kernel, do_binary=do_binary)

    if (method == 'fft'):         # Very fast method

        # Set up a constraint for the fit. It should be different for 1x1 and 4x4.
        # For 1x1, it works well to be 100 pixels.

        if (hbt.sizex(im) == 1024):    # For LORRI 1x1
            constraint_tx    = (0,100) # Mean and stdev. i.e., returned value will be within stdev of mean.
            constraint_ty    = (0,100) 
            
        if (hbt.sizex(im) == 256):   # For LORRI 4x4 
            constraint_tx    = (0,25) # Mean and stdev. i.e., returned value will be within stdev of mean.
            constraint_ty    = (0,25)  
            
        constraint_angle = 0    # With one value, it is a fixed constraint.
        
        constraints = {'tx' : constraint_tx, 'ty' : constraint_ty, 'angle' : constraint_angle}
        ird.translation(image_cat, image_phot, constraints=constraints)
        
        (dy, dx) = ird.translation(image_cat, image_phot, constraints=constraints)['tvec']         
        dy_opnav = -dy
        dx_opnav = -dx

    if (method == 'bruteforce'):  # Very slow method

        ((dx, dy), mat)       = hbt.get_translation_images_bruteforce(image_cat, image_phot)
        dx_opnav = -dx
        dy_opnav = -dy
        
#==============================================================================
# Make a plot, showing DAO positions + catalog positions
#==============================================================================

    do_plot = True
    if (do_plot):
        
#        hbt.figsize((10,10))
        
        plt.imshow(stretch(im))
        
        # Plot the stars -- catalog, and DAO
        
        plt.plot(x_stars_cat + dx_opnav, y_stars_cat + dy_opnav, 
                 marker='o', ls='None', 
                 color=color_cat, alpha = 0.5, ms=12, mew=1, label = 'Cat Stars, adjusted')
        
        plt.plot(x_stars_cat, y_stars_cat, 
                 marker='o', ls='None', 
                 color=color_cat, alpha = 1, ms=4, mew=1, label = 'Cat Stars, raw')
                 
        plt.plot(x_stars_phot, y_stars_phot, 
                 marker='o', ls='None', 
                 color='none', markersize=10, mew=1, mec=color_phot, alpha = 1, label = 'DAOfind Stars')               
        
        plt.title('After navigation, with dx = {:.1f}, dy = {:.1f}, {}'.format(dx_opnav, dy_opnav, title))
        plt.legend()  # Draw legend. Might be irrel since remove() might keep it; not sure.
        
        plt.imshow(stretch(im))
        plt.show()

#==============================================================================
# Return results and exit
#==============================================================================

# Results are returned in terms of pixel offset and a revised WCS structure.
# I don't seem to be able to copy a WCS structure, so I modify the one in place!

# Get the pixel location of the center position

    crpix = wcs_in.wcs.crpix  # Center position, in pixels, old
    
# Get the new RA, Dec center of the array. It is just the old location, plus the offset
    
    ORIGIN_FORMAT = 1  # 0 for Numpy-style indexing, 1 for Fortran-style and FITS-style.
                       # So what do I used for FITS files in python? Experimentally, 1 is right and 0 is not.
    
    (ra_new, dec_new) = wcs_in.wcs_pix2world(crpix[0] - dx_opnav, crpix[1] - dy_opnav, ORIGIN_FORMAT)

    # Set it
    
    wcs_in.wcs.crval = (ra_new, dec_new)
    
    return(wcs_in, (dy_opnav, dx_opnav))    
Example #15
0
def get_fits_table_from_server(catalog, server, ra, dec, sr):
    """
    This function fetches sources from the specified catalog from the specified
    server within the search radius and returns a Table containing them.

    Parameters
    ----------
    catalog: str [sdss9 | 2mass | ukidss9 | gmos]
        name of catalog to search
    server: str
        name of server to query [sdss9_mko | sdss9_cpo | sdss9_vizier |
        2mass_mko | 2mass_cpo | 2mass_vizier | ukidss9_mko | ukidss9_cpo]
    ra: float
        right ascension of search center, decimal degrees
    dec: float
        declination of search center, decimal degrees
    sr: float
        search radius, decimal degrees
    Returns
    -------
    Table
        sources within the search cone
    """
    # This defines the URL for each server
    # There must be an entry in this dictionary for each server
    # listed in cat_servers above
    server_urls = {
        'sdss9_mko': "http://mkocatalog2/cgi-bin/conesearch.py?CATALOG=sdss9&",
        'sdss9_cpo': "http://cpocatalog2/cgi-bin/conesearch.py?CATALOG=sdss9&",
        'sdss9_vizier':
            "http://vizier.u-strasbg.fr/viz-bin/votable/-A?-source=sdss9&",
        '2mass_mko':
            "http://mkocatalog2/cgi-bin/conesearch.py?CATALOG=twomass_psc&",
        '2mass_cpo':
            "http://cpocatalog2/cgi-bin/conesearch.py?CATALOG=twomass_psc&",
        '2mass_vizier':
            "http://vizier.u-strasbg.fr/viz-bin/votable/-A?-source=B/2mass&",
        'ukidss9_mko':
            "http://mkocatalog2/cgi-bin/conesearch.py?CATALOG=ukidss&",
        'ukidss9_cpo':
            "http://cpocatalog2/cgi-bin/conesearch.py?CATALOG=ukidss&",
        'gmos_mko': "http://mkocatalog2/cgi-bin/conesearch.py?CATALOG=gmos&",
        'gmos_cpo': "http://cpocatalog2/cgi-bin/conesearch.py?CATALOG=gmos&",
    }

    # This defines the column names *we* will use for that catalog.
    # There must be one entry in this list for each catalog listed
    # in cat_servers above
    cat_cols = {
        'sdss9': ['catid', 'raj2000', 'dej2000', 'umag', 'umag_err',
                  'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                  'imag_err', 'zmag', 'zmag_err'],
        '2mass': ['catid', 'raj2000', 'dej2000', 'jmag', 'jmag_err',
                  'hmag', 'hmag_err', 'kmag', 'kmag_err'],
        'ukidss9': ['catid', 'raj2000', 'dej2000', 'ymag', 'ymag_err',
                    'zmag', 'zmag_err', 'jmag', 'jmag_err',
                    'hmag', 'hmag_err', 'kmag', 'kmag_err'],
        'gmos': ['name', 'raj2000', 'dej2000', 'umag', 'umag_err',
                 'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                 'imag_err', 'zmag', 'zmag_err']
    }

    # This defines the column name mapping for each catalog server to our
    # column names. This copes with both variable server conventions, and
    # also allows us to point to different columns in the upstream catalog
    # - eg different model fits magnitides - if we wish
    # ***** These need to be in the same order as the list in our_cols *****
    server_colmap = {
        'sdss9_mko': ['objid', 'raj2000', 'dej2000', 'umag', 'umag_err',
                      'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                      'imag_err', 'zmag', 'zmag_err'],
        'sdss9_cpo': ['objid', 'raj2000', 'dej2000', 'umag', 'umag_err',
                      'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                      'imag_err', 'zmag', 'zmag_err'],
        'sdss9_vizier': ['objID', 'RAJ2000', 'DEJ2000', 'umag', 'e_umag',
                         'gmag', 'e_gmag', 'rmag', 'e_rmag', 'imag', 'e_imag',
                         'zmag', 'e_zmag'],
        '2mass_mko': ['designation', 'ra', 'decl', 'j_m', 'j_cmsig',
                      'h_m', 'h_cmsig', 'k_m', 'k_cmsig'],
        '2mass_cpo': ['designation', 'ra', 'decl', 'j_m', 'j_cmsig',
                      'h_m', 'h_cmsig', 'k_m', 'k_cmsig'],
        '2mass_vizier': ['_2MASS', 'RAJ2000', 'DEJ2000', 'Jmag', 'Jcmsig',
                         'Hmag', 'Hcmsig', 'Kmag', 'Kcmsig'],
        'ukidss9_mko': ['id', 'raj2000', 'dej2000', 'y_mag', 'y_mag_err',
                        'z_mag', 'z_mag_err', 'j_mag', 'j_mag_err',
                        'h_mag', 'h_mag_err', 'k_mag', 'k_mag_err'],
        'ukidss9_cpo': ['id', 'raj2000', 'dej2000', 'y_mag', 'y_mag_err',
                        'z_mag', 'z_mag_err', 'j_mag', 'j_mag_err',
                        'h_mag', 'h_mag_err', 'k_mag', 'k_mag_err'],
        'gmos_mko': ['name', 'raj2000', 'dej2000', 'umag', 'umag_err',
                     'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                     'imag_err', 'zmag', 'zmag_err'],
        'gmos_cpo': ['name', 'raj2000', 'dej2000', 'umag', 'umag_err',
                     'gmag', 'gmag_err', 'rmag', 'rmag_err', 'imag',
                     'imag_err', 'zmag', 'zmag_err']
    }

    # OK, do the query
    url = server_urls[server]
    cols = cat_cols[catalog]
    server_cols = server_colmap[server]

    # print "RA, Dec, radius:", ra, dec, sr
    # print "catalog: %s" % catalog
    # print "server: %s" % server
    # print "url: %s" % url
    # print "cols       : %s" % cols
    # print "server_cols: %s" % server_cols
    # print "\n\n"

    # turn on verbose for debug to stdout.
    # Need verb=3 to get the right cols from vizier

    try:
        from astroquery.vo_conesearch.conesearch import conesearch
        from astroquery.vo_conesearch.exceptions import VOSError
    except ImportError:
        # conesearch was deprecated in astropy 2.0 and removed in 3.0, and
        # moved to astroquery 0.3.5
        from astropy.vo.client.conesearch import conesearch
        from astropy.vo.client.vos_catalog import VOSError

    # The following phrase is implemented to handle differing function
    # signatures and return behaviours of vo conesearch function. Under
    # astropy, conesearch throws a VOSError exception on no results. Which
    # seems a bit extreme. See the import phrase at top.
    try:
        try:
            # astroquery 0.4 removed the pedantic keyword in favor of the
            # config item, and switched to returning an astropy table by
            # default (hence return_astropy_table=False below).
            # Another change is that conesearch returns None and issue of
            # NoResultsWarning if no results are found, instead of raising
            # a VOSError.
            # https://github.com/astropy/astroquery/pull/1528
            table = conesearch((ra, dec), sr, verb=3, catalog_db=url,
                               return_astropy_table=False, verbose=False)
        except TypeError:
            table = conesearch((ra, dec), sr, verb=3, catalog_db=url,
                               pedantic=False, verbose=False)
    except VOSError:
        log.stdinfo("VO conesearch produced no results")
        return

    # Did we get any results?
    if(table is None or table.is_empty() or len(table.array) == 0):
        log.stdinfo("No results returned")
        return

    # It turns out to be not viable to use UCDs to select the columns,
    # even for the id, ra, and dec. Even with vizier. <sigh>
    # The first column is our running integer column
    ret_table = Table([list(range(1, len(table.array[server_cols[0]])+1))],
                      names=('Id',), dtype=('i4',))

    ret_table.add_column(Column(table.array[server_cols[0]], name='Cat_Id',
                                dtype='a'))
    ret_table.add_column(Column(table.array[server_cols[1]], name='RAJ2000',
                                dtype='f8', unit='deg'))
    ret_table.add_column(Column(table.array[server_cols[2]], name='DEJ2000',
                                dtype='f8', unit='deg'))

    # Now the photometry columns
    for col in range(3, len(cols)):
        ret_table.add_column(Column(table.array[server_cols[col]], name=cols[col],
                                    dtype='f4', unit='mag', format='8.4f'))

    header = add_header_to_table(ret_table)
    header['CATALOG'] = (catalog.upper(), 'Origin of source catalog')
    # Add comments to the header to describe it
    header.add_comment('Source catalog derived from the {} catalog'.
                       format(catalog))
    header.add_comment('Source catalog fetched from server at {}'.format(url))
    header.add_comment('Delivered Table name from server:  {}'.
                       format(table.name))
    for col in range(len(cols)):
        header.add_comment('UCD for field {} is {}'.format(
            cols[col], table.get_field_by_id(server_cols[col]).ucd))
    return ret_table
Example #16
0
def navigate_image_stellar(im,
                           wcs_in,
                           name_catalog='',
                           do_plot=True,
                           method='fft',
                           title=''):
    """
    Navigate frame based on stellar images.
    Result returns is pixel shift (dy, dx).
    WCS paramaters are returned, *and* modified in place.
    """

    import imreg_dft as ird
    from astropy.wcs import WCS

    # from   astropy.vo.client import conesearch # Virtual Observatory, ie star catalogs   # DEPRECATED!
    from astroquery.vo_conesearch import conesearch  # New home of conesearch

    # Inputs are the image array, and the WCS structure.
    # This routine does not do any file IO. The image array and header must be already loaded.
    # The image is assumed to be stretched properly s.t. stars can be found using DAOphot.

    NUM_STARS_PHOT = 100  # How many stars to use from DAOPhot. For noisy images, DAO will find a lot of
    # fake stars, so we need to crank this up higher than the # of cat stars.
    NUM_STARS_CAT = 50  # How many stars to use from star catalog

    DO_GSC1 = False
    DO_GSC12 = True
    DO_USNOA2 = False

    #==============================================================================
    # Calculate the image radius, in radians, based on the size and the pixel scale
    #==============================================================================

    dx_pix = hbt.sizex(im)
    dy_pix = hbt.sizey(im)
    radec_corner = wcs_in.wcs_pix2world(0, dy_pix / 2, 0)
    radec_center = wcs_in.wcs_pix2world(dx_pix / 2, dy_pix / 2, 0)
    (ra_corner, dec_corner) = radec_corner
    (ra_center, dec_center) = radec_center

    radius_image = math.sqrt((dec_corner - dec_center)**2 + (
        (ra_corner - ra_center) / np.cos(dec_corner * hbt.d2r))**2) * hbt.d2r

    radius_search_deg = radius_image * hbt.r2d

    # Read the WCS coordinates

    center_deg = wcs_in.wcs.crval  # degrees. # crval is a two-element array of [RA, Dec], in degrees

    # Stretch the image. This is just for display -- no processing.

    stretch_percent = 90
    stretch = astropy.visualization.PercentileInterval(
        stretch_percent)  # PI(90) scales array to 5th .. 95th %ile.

    # Display it

    if (do_plot):
        plt.imshow(stretch(im))

#==============================================================================
# Get stars from star catalogs
#==============================================================================

    if (DO_GSC1):
        name_cat = u'The HST Guide Star Catalog, Version 1.1 (Lasker+ 1992) 1'  # works, but 1' errors; investigating
        stars = conesearch.conesearch(center_deg,
                                      radius_search_deg,
                                      cache=True,
                                      catalog_db=name_cat)
        ra_stars = np.array(
            stars.array['RAJ2000']) * hbt.d2r  # Convert to radians
        dec_stars = np.array(
            stars.array['DEJ2000']) * hbt.d2r  # Convert to radians
    #            table_stars = Table(stars.array.data)

    if (DO_GSC12):
        #        name_cat = u'The HST Guide Star Catalog, Version 1.2 (Lasker+ 1996) 1'
        name_cat = u'Guide Star Catalog v2 1'  # Works from gobi, not tomato
        url_cat = 'http://gsss.stsci.edu/webservices/vo/ConeSearch.aspx?CAT=GSC23&'  # Works always

        with data.conf.set_temp(
                'remote_timeout',
                30):  # This is the very strange syntax to set a timeout delay.
            # The default is 3 seconds, and that times out often.
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                # stars = conesearch.conesearch(wcs_in.wcs.crval, radius_search_deg, cache=True, catalog_db = url_cat)

                # The various functions of conesearch/ConeSearch/etc are quite confusing, and are in flux.
                # This line below seems to work. It does not allow an explicit catalog suggstion, but it does the job.

                c = astropy.coordinates.SkyCoord(wcs_in.wcs.crval[0],
                                                 wcs_in.wcs.crval[1],
                                                 unit='deg')
                stars = ConeSearch.query_region(c, f'{radius_search_deg} deg')

        ra_stars = np.array(stars.array['ra']) * hbt.d2r  # Convert to radians
        dec_stars = np.array(
            stars.array['dec']) * hbt.d2r  # Convert to radians

        mag = np.array(stars.array['Mag'])

        print("Stars downloaded: N = {}; mag = {:.2f} .. {:.2f}".format(
            np.size(mag), np.nanmin(mag), np.nanmax(mag)))
        print("RA = {:.2f} .. {:.2f}".format(
            np.nanmin(ra_stars) * hbt.r2d,
            np.nanmax(ra_stars) * hbt.r2d))

        # Now sort by magnitude, and keep the 100 brightest
        # This is because this GSC catalog is huge -- typically 2000 stars in LORRI FOV.
        # We need to reduce its size to fit in our fixed astropy table string length.

        order = np.argsort(mag)
        order = np.array(order)[0:NUM_STARS_CAT]

        ra_stars = ra_stars[order]  # Returned as radians
        dec_stars = dec_stars[order]

    if (DO_USNOA2):
        name_cat = u'The USNO-A2.0 Catalogue (Monet+ 1998) 1'  # Works but gives stars down to v=17; I want to v=13
        stars = conesearch.conesearch(wcs_in.wcs.crval,
                                      0.3,
                                      cache=False,
                                      catalog_db=name_cat)
        table_stars = Table(stars.array.data)
        mask = table_stars['Bmag'] < 13
        table_stars_m = table_stars[mask]

        ra_stars = table_stars_m['RAJ2000'] * hbt.d2r  # Convert to radians
        dec_stars = table_stars_m['DEJ2000'] * hbt.d2r  # Convert to radians

    ra_stars_cat = ra_stars
    dec_stars_cat = dec_stars

    radec_stars_cat = np.transpose(np.array((ra_stars_cat, dec_stars_cat)))

    (x_stars_cat,
     y_stars_cat) = wcs_in.wcs_world2pix(radec_stars_cat[:, 0] * hbt.r2d,
                                         radec_stars_cat[:, 1] * hbt.r2d, 0)

    points_stars_cat = np.transpose(
        (y_stars_cat, x_stars_cat))  # Yes, order is supposed to be (y,x)

    #==============================================================================
    # Use DAOphot to search the image for stars.
    #==============================================================================

    points_stars_phot = hbt.find_stars(
        im,
        num=NUM_STARS_PHOT)  # Returns N x 2 aray. 0 = Row = y; 1 = Column = x.

    y_stars_phot = (points_stars_phot[:, 0])  # xy is correct -- see above
    x_stars_phot = (points_stars_phot[:, 1])  #

    #==============================================================================
    # Make a plot showing the DAO stars on the image
    #==============================================================================

    color_phot = 'red'  # Color for stars found photometrically
    color_cat = 'lightgreen'  # Color for stars in catalog

    DO_PLOT_DAO = False  # Plot an intermediate result?

    if (DO_PLOT_DAO):

        plt.imshow(stretch(im))

        plt.plot(x_stars_phot,
                 y_stars_phot,
                 linestyle='none',
                 marker='o',
                 markersize=9,
                 mec=color_cat,
                 mew=1,
                 color='none',
                 label='DAO photometric stars')  # plot() uses x, y

        plt.plot(x_stars_cat,
                 y_stars_cat,
                 linestyle='none',
                 marker='o',
                 markersize=5,
                 color='lightgreen',
                 label='Cat stars')  # plot() uses x, y

        plt.title(title)
        plt.ylim((hbt.sizey(im)), 0)
        plt.xlim((0, hbt.sizex(im)))
        plt.legend(loc='upper left')
        plt.show()

# Up til here, x and y are correct

#==============================================================================
# Look up the shift between the photometry and the star catalog.
# Do this by making a pair of fake images, and then looking up image registration on them.
#==============================================================================

# I call this pointing process 'opnav'.
# It is returned in order (y,x) because that is what imreg_dft uses, even though it is a bit weird.

    diam_kernel = 11  # How many pixels across are our synthetic stellar images? Should be odd number. Not critical.
    do_binary = True  # For the stellar images, do a binary 1/0 (recommended), or a pixel distance?

    shape = np.shape(im)  # Set shape of output array

    image_cat = hbt.image_from_list_points(points_stars_cat,
                                           shape,
                                           diam_kernel,
                                           do_binary=do_binary)
    image_phot = hbt.image_from_list_points(points_stars_phot,
                                            shape,
                                            diam_kernel,
                                            do_binary=do_binary)

    if (method == 'fft'):  # Very fast method

        # Set up a constraint for the fit. It should be different for 1x1 and 4x4.
        # For 1x1, it works well to be 100 pixels.

        if (hbt.sizex(im) == 1024):  # For LORRI 1x1
            constraint_tx = (
                0, 100
            )  # Mean and stdev. i.e., returned value will be within stdev of mean.
            constraint_ty = (0, 100)

        if (hbt.sizex(im) == 256):  # For LORRI 4x4
            constraint_tx = (
                0, 25
            )  # Mean and stdev. i.e., returned value will be within stdev of mean.
            constraint_ty = (0, 25)

        constraint_angle = 0  # With one value, it is a fixed constraint.

        constraints = {
            'tx': constraint_tx,
            'ty': constraint_ty,
            'angle': constraint_angle
        }
        ird.translation(image_cat, image_phot, constraints=constraints)

        (dy, dx) = ird.translation(image_cat,
                                   image_phot,
                                   constraints=constraints)['tvec']
        dy_opnav = -dy
        dx_opnav = -dx

    if (method == 'bruteforce'):  # Very slow method

        ((dx, dy),
         mat) = hbt.get_translation_images_bruteforce(image_cat, image_phot)
        dx_opnav = -dx
        dy_opnav = -dy

#==============================================================================
# Make a plot, showing DAO positions + catalog positions
#==============================================================================

    do_plot = True
    if (do_plot):

        #        hbt.figsize((10,10))

        plt.imshow(stretch(im))

        # Plot the stars -- catalog, and DAO

        plt.plot(x_stars_cat + dx_opnav,
                 y_stars_cat + dy_opnav,
                 marker='o',
                 ls='None',
                 color=color_cat,
                 alpha=0.5,
                 ms=12,
                 mew=1,
                 label='Cat Stars, adjusted')

        plt.plot(x_stars_cat,
                 y_stars_cat,
                 marker='o',
                 ls='None',
                 color=color_cat,
                 alpha=1,
                 ms=4,
                 mew=1,
                 label='Cat Stars, raw')

        plt.plot(x_stars_phot,
                 y_stars_phot,
                 marker='o',
                 ls='None',
                 color='none',
                 markersize=10,
                 mew=1,
                 mec=color_phot,
                 alpha=1,
                 label='DAOfind Stars')

        plt.title('After navigation, with dx = {:.1f}, dy = {:.1f}, {}'.format(
            dx_opnav, dy_opnav, title))
        plt.legend(
        )  # Draw legend. Might be irrel since remove() might keep it; not sure.

        plt.imshow(stretch(im))
        plt.show()

#==============================================================================
# Return results and exit
#==============================================================================

# Results are returned in terms of pixel offset and a revised WCS structure.
# I don't seem to be able to copy a WCS structure, so I modify the one in place!

# Get the pixel location of the center position

    crpix = wcs_in.wcs.crpix  # Center position, in pixels, old

    # Get the new RA, Dec center of the array. It is just the old location, plus the offset

    ORIGIN_FORMAT = 1  # 0 for Numpy-style indexing, 1 for Fortran-style and FITS-style.
    # So what do I used for FITS files in python? Experimentally, 1 is right and 0 is not.

    (ra_new, dec_new) = wcs_in.wcs_pix2world(crpix[0] - dx_opnav,
                                             crpix[1] - dy_opnav,
                                             ORIGIN_FORMAT)

    # Set it

    wcs_in.wcs.crval = (ra_new, dec_new)

    return (wcs_in, (dy_opnav, dx_opnav))
index_asymptote = 0 if (encounter_phase == 'Outbound') else 1

# We make one call to SPICE to look up the asymptote position
# Most SPICE calls are later, but we need to do this one now, ahead of order.

(st,lt) = sp.spkezr('MU69', et[index_asymptote], 'J2000', 'LT', 'New Horizons')
(junk, ra_asymptote, dec_asymptote) = sp.recrad(st[0:3])   
crval = np.array([ra_asymptote, dec_asymptote]) * hbt.r2d
                  
radius_search = 0.15 # degrees # We only use these catalog for very fine searches, so narrow is OK.

DO_PLOT_GSC = False # Goes to about v=12

if DO_PLOT_GSC:                 
    name_cat = u'The HST Guide Star Catalog, Version 1.1 (Lasker+ 1992) 1' # works, but 1' errors; investigating
    stars = conesearch.conesearch(crval, radius_search, cache=False, catalog_db = name_cat)
    ra_stars  = np.array(stars.array['RAJ2000'])*hbt.d2r # Convert to radians
    dec_stars = np.array(stars.array['DEJ2000'])*hbt.d2r # Convert to radians
    mag_stars = np.array(stars.array['Pmag'])

if DO_PLOT_USNO:                 
    name_cat = u'The USNO-A2.0 Catalogue (Monet+ 1998) 1'
    stars = conesearch.conesearch(crval, radius_search, cache=False, catalog_db = name_cat)
    ra_stars  = np.array(stars.array['RAJ2000'])*hbt.d2r # Convert to radians
    id_stars = np.array(stars.array['USNO-A2.0']) # ID
    id_stars = id_stars.astype('U') # Convert from byte string to Unicode, ugh.
    dec_stars = np.array(stars.array['DEJ2000'])*hbt.d2r # Convert to radians
    mag_b_stars = np.array(stars.array['Bmag'])
    mag_r_stars = np.array(stars.array['Rmag'])

    usno = Table([id_stars, ra_stars, dec_stars, mag_b_stars, mag_r_stars],