Пример #1
0
def get_source_images(target,
                      survey_list,
                      pixels=512,
                      folder='./',
                      verbose=False):
    '''
  Download postagestamp images of targets from SkyView
  
  :param target: An astropy table row containing the name and coordinates of the target
  :param survey_list: A list of strings containing survey names
  :param pixels: An integer, the dimensions of the requested (square) image
  :param folder: A string, the location where downloaded images should be saved
  :param verbose: A boolean, determine whether or not to print errors
  
  '''

    paths = SkyView.get_image_list(
        position='%s, %s' % (target['ra'], target['dec']), survey=survey_list
    )  # can't use get_image() because it throws errors when files don't exist

    for survey, path in zip(survey_list, paths):
        filepath = "%s%s_%s.fits" % (folder, target['full_name'], survey)
        filepath = filepath.replace(' ', '_')

        try:
            urllib.request.urlretrieve(path, filepath)
        except urllib.error.HTTPError:
            if verbose:
                print("%s not in %s" % (target['full_name'], survey))
            pass
Пример #2
0
def Planck_SkyView(name, ra, dec, width, band, bands_dict, temp_dir):
    print('Querying for Planck ' + bands_dict[band]['wavelength'] +
          'um data for ' + name + ' from NASA SkyView')
    position_string = str(ra) + ' ' + str(dec)
    query_success = None
    pix_size = bands_dict[band]['pix_size']

    # Add tiny permutation to width to stop SkyView flailing over repeat queries
    width *= 1.0 + (0.01 * (np.random.rand() - 0.5))

    # Perform query
    while query_success == None:
        try:
            query_filename = os.path.join(
                temp_dir,
                name + '_Planck_' + bands_dict[band]['wavelength'] + '.fits')
            query_url = SkyView.get_image_list(
                position_string,
                bands_dict[band]['band_name'],
                deedger='_skip_',
                pixels=int((width * 3600.0) / pix_size),
                radius=astropy.units.Quantity(width, unit='deg'))
            if len(query_url) != 1:
                pdb.set_trace()
            query_success = True
        except:
            query_success = False

    # Retrieve and verify data
    if query_success:
        print('Retrieving identified Planck ' +
              bands_dict[band]['wavelength'] + 'um data for ' + name)
        Planck_wget(str(query_url[0]), query_filename)
        try:
            astropy.io.fits.info(query_filename)
        except Exception:
            query_success = False
            pdb.set_trace()

    # If no data available, generate null file and report failure
    if not query_success:
        os.system('touch ' + os.path.join(
            temp_dir, '.' + name + '_Planck_' +
            bands_dict[band]['wavelength'] + '.null'))
        print('No ' + band + ' data for ' + name)
def Planck_SkyView(name, ra, dec, width, band, bands_dict, out_dir):
    print('Retrieving ' + band + ' data for ' + name + ' from NASA SkyView')
    position_string = str(ra) + ' ' + str(dec)
    query_success = None
    query_reattempt = False
    pix_size = bands_dict[band]['pix_size']

    # Perform query
    while query_success == None:
        try:
            query_filename = os.path.join(
                out_dir,
                name + '_Planck_' + bands_dict[band]['wavelength'] + '.fits')
            query_url = SkyView.get_image_list(
                position_string,
                bands_dict[band]['band_name'],
                deedger='_skip_',
                pixels=str(int((width * 3600.0) / pix_size)),
                radius=astropy.units.Quantity(width, unit='deg'))
            if len(query_url) != 1:
                pdb.set_trace()
            query_success = True
        except:
            query_success = False

    # Retrieve and verify data
    if query_success:
        print('Retrieving identified Planck ' + band + ' data for ' + name)
        Planck_wget(str(query_url[0]), query_filename)
        try:
            astropy.io.fits.info(query_filename)
        except Exception as exception:
            if exception.message == 'Empty or corrupt FITS file':
                pdb.set_trace()
            else:
                pdb.set_trace()

    # Report failure
    if not query_success:
        print('No Planck ' + band + ' data for ' + name)
        pdb.set_trace()
def get_url(coords, surveys, radius=None, width=None, height=None):
    print('Reading urls')
    urls = []
    valid_surveys = []
    missing_surveys = []
    for survey in surveys:
        url = SkyView.get_image_list(position=coords,
                                 survey=survey,
                                 radius=radius,
                                 width=width,
                                 height=height)
        if url != []:
            if requests.get(url[0]).status_code != 404:
                urls.append(url)
                valid_surveys.append(survey)
            print('OK:     ', survey)
        else:
            missing_surveys.append(survey)
            print('Failed: ', survey)
    for u,s in zip(urls, valid_surveys):
        print(u,s)
    return urls, valid_surveys, missing_surveys
        for ii,ind in enumerate(select_ind):
            radec_hmsdms = coords[ind].to_string('hmsdms')
            try:
                imgfiles = SkyView.get_images(radec_hmsdms, survey=survey, pixels=pixels, coordinates=coordinfo['epoch'], projection=projection)
            except Exception as err:
                warnings.warn('Problem with retrieving image at {0}.\nEncountered error: {1}.\nProceeding to the next object...\n'.format(radec_hmsdms, err.message), Warning)

                if isinstance(err, AttributeError):
                    # For some reason, timeouts come under Attribute Error.
                    # There will be retries on these failures, but not others
                    # such as pointing outside the survey area, etc.

                    failure_count += 1
                    failed_coords += [radec_hmsdms]
            else:
                paths += [SkyView.get_image_list(radec_hmsdms, survey=survey, pixels=pixels, coordinates=coordinfo['epoch'], projection=projection)[0]]
                success_coords += [radec_hmsdms]
                print('Successfully located {0} [{1:0d}/{2:0d}]'.format(radec_hmsdms, len(paths), select_ind.size))

        if failure_count > 0:
            # Process the failures
            failurefile = projectdir + parms['failure']['failurefile']
            n_retry = parms['failure']['retry']
            if n_retry > 0:
                # Retry the failed retrievals
                for iretry in range(n_retry):
                    if len(success_coords) < len(failed_coords):
                        for indfail, failcoord in enumerate(failed_coords):
                            if failcoord not in success_coords:
                                try:
                                    imgfiles = SkyView.get_images(failcoord, survey=survey, pixels=pixels, coordinates=coordinfo['epoch'], projection=projection)
Пример #6
0
def gmos_twotarget(name,
                   ra1,
                   dec1,
                   ra2,
                   dec2,
                   pm_ra_cosdec1=0.0,
                   pm_dec1=0.0,
                   pm_ra_cosdec2=0.0,
                   pm_dec2=0.0,
                   slitwidth=1,
                   pnum='Gemini GMOS Spectroscopy',
                   skysurvey="DSS",
                   frame='fk5',
                   unit='deg',
                   epoch='J2000',
                   time_obs='J2020',
                   corner='bottom left'):
    """
    Function to create gmos finding charts from archive sky images, given the target coordinates, proper motions and epoch of observation.
    Currently, the proper motion translation of the final finding charts is disabled, and the finding chart is produced in J2000 coordinate system.  However, the proper motion of the target is calculated for the observational epoch. If the new coordinates are significantly different to the (1st decimal degree) J2000 coordinates, the finding charts maybe inaccurate.
    
    Returns finding charts for two GMOS targets at given coordinates.
    
    Parameters:
    name: String
    The name of the target.
    
    ra1: float
    Right Ascension of the user 1 in J2000 Fk5 system.
    
    dec1: float
    Declination of the user 1 in J2000 Fk5 system.
    
    ra2: float
    Right Ascension of the user 2 in J2000 Fk5 system.
    
    dec2: float
    Declination of the user 2 in J2000 Fk5 system.

    
    pm_ra_cosdec1: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    pm_dec1: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    pm_ra_cosdec2: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    pm_dec2: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    slitwidth: float, optional
    Slit width of the GMOS slit in arcsec. Default is 1 arcsec.
    
    pnum: String, optional
    Gemini Program ID. Defaults to GMOS spectropscopy.
    
    unit: string, or tuple, optional
    Units of the coordinates following astropy.Skycoord system. Default is decimal degrees.
    
    epoch: String, optional
    Epoch of the coordinates of the target. Default is set to J2000.
    
    time_obs: String, optional
    Epoch of when the obsevations will take place. Default is J2020.
    
    corner: String, optional
    Position of scalebar in the finding chart, following from aplpy convention
    Acceptable values are top right, top left, bottom right, bottom left, left, right, bottom or top.


    
    """
    ##### Parsec input parameters
    time_obs = Time(time_obs, format='jyear_str')
    epoch = Time(epoch, format='jyear_str')

    pm_ra_cosdec1 = pm_ra_cosdec1 * u.mas / u.yr
    pm_dec1 = pm_dec1 * u.mas / u.yr
    coords1 = SkyCoord(ra1,
                       dec1,
                       unit=unit,
                       pm_ra_cosdec=pm_ra_cosdec1,
                       pm_dec=pm_dec1,
                       frame=frame,
                       obstime=epoch)
    coordsnew1 = coords1.transform_to(FK5(equinox=time_obs))

    pm_ra_cosdec2 = pm_ra_cosdec2 * u.mas / u.yr
    pm_dec2 = pm_dec2 * u.mas / u.yr
    coords2 = SkyCoord(ra2,
                       dec2,
                       unit=unit,
                       pm_ra_cosdec=pm_ra_cosdec2,
                       pm_dec=pm_dec2,
                       frame=frame,
                       obstime=epoch)
    coordsnew2 = coords2.transform_to(FK5(equinox=time_obs))

    ##### Calculate separation

    sep = coords2.separation(coords1)
    sep_arcsec = sep.arcsec
    if sep_arcsec > 330.:
        raise Exception(
            "A star too far! Please check your coordinates, as the separation between User 1 and User 2 targets exceeds the recommended limit at {}"
            .format(sep_arcsec))

    print('The coordinates of', name, 'User 1 target in the epoch',
          time_obs.value, 'are RA=', round(coordsnew1.ra.value, 5), ',DEC=',
          round(coordsnew1.dec.value, 5))

    print('The coordinates of', name, 'User 2 target in the epoch',
          time_obs.value, 'are RA=', round(coordsnew2.ra.value, 5), ',DEC=',
          round(coordsnew2.dec.value, 5))

    ###### Calculate position angle and Base coordinates

    meanra = (coords1.ra.to_value() + coords2.ra.to_value()) / 2
    meandec = (coords1.dec.to_value() + coords2.dec.to_value()) / 2

    coords = SkyCoord(meanra, meandec, unit=unit, frame=frame, obstime=epoch)

    pa = coords1.position_angle(coords2).degree

    log.info("The position angle is %+.2f" % pa)
    log.info("The Base target in Right Ascencsion (J2000) is %+.2f" % meanra)
    log.info("The Base target in Declination is (J2000) is %+.2f" % meandec)

    ###### Create the sky survey image
    imageurl = SkyView.get_image_list(position=coords,
                                      survey=skysurvey,
                                      coordinates="J2000",
                                      height=7 * u.arcmin,
                                      width=7 * u.arcmin)
    filename = wget.download(imageurl[0])
    gaia_image = str(filename)

    ######
    ######
    print('Creating finding chart using archival survey imaging for', name)

    ###### Create overlay of slit
    ###### Shift position angle by 90 to display in ds9.
    ###### pyregion is obselete
    pa = Angle(pa * u.deg)
    pa = pa.value
    slitwidth = slitwidth * u.arcsec
    slitwidths = (3.5 * slitwidth.value)
    writeregion(name, coords.ra.value, coords.dec.value, slitwidths, pa + 90)
    pa = round(pa, 1)

    ######## Create figure
    ######## TeX instances removed for broaded compatability.
    fig = plt.figure()
    gc = aplpy.FITSFigure(gaia_image, north=True, figure=fig)
    gc.show_grayscale(stretch='linear', invert=True)
    gc.frame.set_linewidth(0.5)  # points
    gc.frame.set_color('black')
    gc.show_markers(coords.ra.value,
                    coords.dec.value,
                    edgecolor='red',
                    facecolor="None",
                    marker='o',
                    s=75,
                    label='Base',
                    lw=0.5)

    gc.show_markers(coords1.ra.value,
                    coords1.dec.value,
                    edgecolor='blue',
                    facecolor="None",
                    marker='s',
                    s=75,
                    label='User1',
                    lw=0.5)
    gc.show_regions(name + ".reg")
    gc.show_markers(coords2.ra.value,
                    coords2.dec.value,
                    edgecolor='green',
                    facecolor="None",
                    marker='s',
                    s=75,
                    label='User2',
                    lw=0.5)
    #gc.show_rectangles([coords.ra.value],[coords.dec.value],0.09166666666666666,slitwidths, angle=pa, edgecolor='blue', lw=0.5, label='pa')
    gc.add_scalebar(1)
    gc.scalebar.show(0.03334,
                     corner=corner,
                     frame=True,
                     borderpad=0.4,
                     pad=0.5)
    gc.scalebar.set_corner(corner)
    gc.scalebar.set_frame(True)
    gc.scalebar.set_color('black')
    gc.scalebar.set_label("$2'$")
    gc.scalebar.set_font(size='small', weight='medium', \
                     stretch='normal', family='serif', \
                     style='normal', variant='normal')
    gc.axis_labels.set_xtext('$\mathrm{Right\,Ascension (J2000)}$')
    gc.axis_labels.set_ytext('$\mathrm{Declination (J2000)}$')
    gc.scalebar.set_font(size='small', weight='medium', \
                     stretch='normal', family='serif', \
                     style='normal', variant='normal')
    gc.axis_labels.set_font(size='medium', weight='medium', \
                        stretch='normal', family='serif', \
                        style='normal', variant='normal')
    gc.ticks.set_color("black")
    gc.tick_labels.set_xformat('hh:mm:ss')
    gc.tick_labels.set_yformat('dd:mm:ss')
    gc.tick_labels.set_font(size='small')
    gc.ticks.set_length(0)
    plt.tick_params(length=6, width=0.6, which='major', tickdir='in')
    plt.tick_params(length=3, which='minor')
    gc.add_grid()
    gc.grid.show()
    gc.grid.set_alpha(0.5)
    ##### Generate compass radius.to(u.deg).value/np.cos(field_center.dec.radian)
    arrow_width = 20 * u.arcsec
    radius = 165 * u.arcsec
    x = coords.ra.value - radius.to(u.deg).value / np.cos(coords.dec.radian)
    y = coords.dec.value - radius.to(u.deg).value
    dx = arrow_width.to(u.deg).value
    dy = arrow_width.to(u.deg).value / np.cos(coords.dec.radian)

    gc.show_arrows(x,
                   y,
                   dx,
                   0.0,
                   color='black',
                   width=2,
                   head_length=5,
                   head_width=5)
    gc.show_arrows(x,
                   y,
                   0.0,
                   dy,
                   color='black',
                   width=2,
                   head_length=5,
                   head_width=5)

    fig.legend(ncol=1)
    gc.add_label(0.07, 0.95, skysurvey, relative=True, color='black')
    title = str(pnum) + str('\n') + str(name) + ' : Two target acquisition'
    fig.suptitle(title, fontsize=12, horizontalalignment='right')
    chartname = name + "_fc.jpg"
    gc.save(chartname, dpi=600, format="jpg")
    gc.close()
    plt.close()
    print('Finding chart saved as', chartname)
    print('Cleaning up')
    os.system("rm " + str(gaia_image))
    os.system("rm " + str(name) + ".reg")
Пример #7
0
'''
'Optical:SDSS': [u'SDSSg',
                  u'SDSSi',
                  u'SDSSr',
                  u'SDSSu',
                  u'SDSSz',
                  u'SDSSdr7g',
                  u'SDSSdr7i',
                  u'SDSSdr7r',
                  u'SDSSdr7u',
                  u'SDSSdr7z'],
'''

#There are two essential methods: get_images searches for
#and downloads files, while get_image_list just searches for the files.
c = "11 43 06.00 53 50 46.01"
c2 = "175.7986916080435 53.84611451646336"
# print SkyView.get_image_list(position= c, survey=['SDSSg'])
# print 'backslash n \n\n'
print SkyView.get_image_list(position=c2,
                             survey=['SDSSg', 'SDSSi', 'SDSSu', 'SDSSz'])
'''
Green (g) 4770
Near Infrared (i) 7625
Red (r) 6231
Ultraviolet (u) 3543
Infrared (z) 9134
and
dr7g
dr7i etc
'''
Пример #8
0
def gmos_blindoffset(name, ra1, dec1, rablind, decblind, pm_ra_cosdec=0.0, pm_dec=0.0, pa=0.0, slitwidth=1, pnum='Gemini GMOS Spectroscopy', skysurvey='DSS', frame='fk5', unit='deg', epoch='J2000', time_obs='J2020', corner='bottom left'):


    """
    Function to create gmos finding charts from sky survey images, given the target coordinates, proper motions and epoch of observation.
    
    Returns finding charts for blind offset GMOS target at given coordinates.
    
    Parameters:
    name: String
    The name of the target.
    
    ra1: float
    Right Ascension of the base target in J2000 Fk5 system.
    
    dec1: float
    Declination of the base target in J2000 Fk5 system.
    
    rablind: float
    Right Ascension of the blind offset target in J2000 Fk5 system.
    
    decblind: float
    Declination of the blind offset target in J2000 Fk5 system.

    
    pm_ra_cosdec: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    pm_dec: float, optional
    Proper motion of the target in mas/yr. Depreciated.
    
    pa: float, optional
    Position angle of the target in decimal degrees. Must be between 0 and 360. Default is 0, not parallitic.
    
    slitwidth: float, optional
    Slit width of the GMOS slit in arcsec. Default is 1 arcsec.
    
    pnum: String, optional
    Gemini Program ID. Defaults to GMOS spectropscopy.
    
    skysurvey: String, optional
    Skysurvey chosen from skyquery function. Options can be found at https://astroquery.readthedocs.io/en/latest/skyview/skyview.html. Defaults to DSS
    
    unit: string, or tuple, optional
    Units of the coordinates following astropy.Skycoord system. Default is decimal degrees.
    
    epoch: String, optional
    Epoch of the coordinates of the target. Default is set to J2000.
    
    time_obs: String, optional
    Epoch of when the obsevations will take place. Default is J2020.
    
    corner: String, optional
    Position of scalebar in the finding chart, following from aplpy convention
    Acceptable values are top right, top left, bottom right, bottom left, left, right, bottom or top.


    
    """
##### Parsec input parameters
    time_obs = Time(time_obs, format='jyear_str')
    epoch = Time(epoch, format='jyear_str')
    
    pm_ra_cosdec = pm_ra_cosdec*u.mas/u.yr
    pm_dec = pm_dec = pm_dec*u.mas/u.yr
    coords = SkyCoord(ra1, dec1, unit=unit, pm_ra_cosdec=pm_ra_cosdec, pm_dec=pm_dec, frame=frame, obstime=epoch)
    coordsnew = coords.transform_to(FK5(equinox=time_obs))
    
    coordsblind = SkyCoord(rablind, decblind, unit=unit, frame=frame, obstime=epoch)
    coordsnewblind = coords.transform_to(FK5(equinox=time_obs))

##### Calculate separation
    
    sep = coordsblind.separation(coords)
    sep_arcsec = sep.arcsec
    if sep_arcsec > 30.:
        raise Exception ("A star too far! Please check your coordinates, as the separation between the Base and blind offset targets exceeds the recommended limit at {}".format(sep_arcsec))

    print ('The coordinates of', name, 'base target in the epoch', time_obs.value, 'are RA=',round(coordsnew.ra.value,5), ',DEC=',round(coordsnew.dec.value,5))
    
    print ('The coordinates of', name, 'in the epoch', time_obs.value, 'are RA=',round(coordsnewblind.ra.value,5), ',DEC=',round(coordsnewblind.dec.value,5))

    
###### Download image
    imageurl = SkyView.get_image_list(position=coords, survey="DSS", coordinates="J2000", height=7*u.arcmin, width=7*u.arcmin)
    filename = wget.download(imageurl[0])
    gaia_image = str(filename)

######
######
    print ('Creating finding chart using archival survey image for', name)
    

###### Create overlay of slit
###### Shift position angle by 90 to display in ds9.
###### pyregion is obselete
    pa = Angle(pa * u.deg)
    pa = pa.value
    slitwidth=slitwidth * u.arcsec
    slitwidths = (3.5*slitwidth.value)
    writeregion(name, coords.ra.value, coords.dec.value, slitwidths, pa+90)
    pa = round(pa,1)


######## Create figure
######## TeX instances removed for broaded compatability.
    fig = plt.figure()
    gc = aplpy.FITSFigure(gaia_image, north=True, figure=fig)
    gc.show_grayscale(stretch='linear', invert=True)
    gc.frame.set_linewidth(0.5)  # points
    gc.frame.set_color('black')
    gc.show_markers(coords.ra.value,coords.dec.value,edgecolor='red', facecolor="None", s=75, label='Base', lw=0.5)
    gc.show_regions(name + ".reg")
    gc.show_markers(coordsblind.ra.value,coordsblind.dec.value,edgecolor='blue', facecolor="None", marker='s', s=75, label='Blind offset', lw=0.5)
 #gc.show_rectangles([coords.ra.value],[coords.dec.value],0.09166666666666666,slitwidths, angle=pa, edgecolor='blue', lw=0.5, label='pa')
    gc.add_scalebar(1)
    gc.scalebar.show(0.03334, corner=corner, frame=True, borderpad=0.4, pad=0.5)
    gc.scalebar.set_corner(corner)
    gc.scalebar.set_frame(True)
    gc.scalebar.set_color('black')
    gc.scalebar.set_label("$2'$")
    gc.scalebar.set_font(size='small', weight='medium', \
                     stretch='normal', family='serif', \
                     style='normal', variant='normal')
    gc.axis_labels.set_xtext('$\mathrm{Right\,Ascension (J2000)}$')
    gc.axis_labels.set_ytext('$\mathrm{Declination (J2000)}$')
    gc.scalebar.set_font(size='small', weight='medium', \
                     stretch='normal', family='serif', \
                     style='normal', variant='normal')
    gc.axis_labels.set_font(size='medium', weight='medium', \
                        stretch='normal', family='serif', \
                        style='normal', variant='normal')
    gc.ticks.set_color("black")
    gc.tick_labels.set_xformat('hh:mm:ss')
    gc.tick_labels.set_yformat('dd:mm:ss')
    gc.tick_labels.set_font(size='small')
    gc.ticks.set_length(0)
    plt.tick_params(length=6, width=0.6, which='major', tickdir='in')
    plt.tick_params(length=3,  which='minor')
    gc.add_grid()
    gc.grid.show()
    gc.grid.set_alpha(0.5)
##### Generate compass radius.to(u.deg).value/np.cos(field_center.dec.radian)
    arrow_width = 20*u.arcsec
    radius = 165*u.arcsec
    x = coords.ra.value-radius.to(u.deg).value/np.cos(coords.dec.radian)
    y = coords.dec.value-radius.to(u.deg).value
    dx = arrow_width.to(u.deg).value
    dy = arrow_width.to(u.deg).value/np.cos(coords.dec.radian)
    
    gc.show_arrows(x,y,dx,0.0, color='black', width=2, head_length=5, head_width=5)
    gc.show_arrows(x,y,0.0,dy, color='black', width=2, head_length=5, head_width=5)

    fig.legend(ncol=1)
    gc.add_label(0.07, 0.95, skysurvey, relative=True, color='black')
    title = str(pnum)+str('\n')+str(name)+' : Blind-offset acquisition'
    fig.suptitle(title, fontsize=12, horizontalalignment='right')
    chartname = name + "_fc.jpg"
    gc.save(chartname, dpi=600, format="jpg")
    gc.close()
    plt.close()
    print ('Finding chart saved as',chartname)
    print ('Cleaning up')
    os.system("rm "+str(gaia_image))
    os.system("rm "+str(name)+".reg")
    def find_assets(self, path: Optional[str] = None,
                    sort_by: Optional[str] = None,
                    page_size: Optional[int] = None,
                    page: Optional[Union[int, str]] = None,
                    survey: str = 'DSS',
                    ra_hours: Optional[float] = None,
                    dec_degs: Optional[float] = None,
                    object: Optional[str] = None,
                    width: Optional[float] = None,
                    height: Optional[float] = None) \
            -> Tuple[TList[DataProviderAsset], None]:
        """
        Return a list of assets matching the given parameters

        Returns an empty list if survey is unknown or no imaging data at the
        given FOV; otherwise, returns a single asset

        :param path: path to the collection asset to search in; ignored
        :param sort_by: unused
        :param page_size: unused
        :param page: unused
        :param survey: survey name; should be one of those returned by
            the /imaging-surveys resource; default: DSS
        :param ra_hours: RA of image center in hours; used in conjunction
            with `dec_degs` and is mutually exclusive with `object`
        :param dec_degs: Dec of image center in degrees; used in conjunction
            with `ra_hours` and is mutually exclusive with `object`
        :param object: object name resolvable by SIMBAD or NED or coordinates
            like "01 23 45.6, +12 34 56.7"
        :param width: image width in arcminutes
        :param height: image height in arcminutes; default: same as `width`

        :return: list of 0 or 1 :class:`DataProviderAsset` objects for assets
            matching the query parameters, and None for the pagination info
        """
        if all(item is None for item in (ra_hours, dec_degs, object)):
            raise MissingFieldError('ra_hours,dec_degs|object')
        if (ra_hours is not None or dec_degs is not None) and \
                object is not None:
            raise ValidationError(
                'ra_hours,dec_degs|object',
                '"ra_hours"/"dec_degs" are mutually exclusive with "object"')
        if object is None and (ra_hours is None or dec_degs is None):
            raise MissingFieldError('ra_hours,dec_degs')
        if width is None and height is None:
            raise MissingFieldError('width,height')
        if ra_hours is not None:
            try:
                ra_hours = float(ra_hours)
                if not 0 <= ra_hours < 24:
                    raise ValueError()
            except ValueError:
                raise ValidationError('ra_hours',
                                      'Expected 0 <= ra_hours < 24')
        if dec_degs is not None:
            try:
                dec_degs = float(dec_degs)
                if not -90 <= dec_degs <= 90:
                    raise ValueError()
            except ValueError:
                raise ValidationError('dec_degs',
                                      'Expected -90 <= dec_degs <= 90')
        if width is not None:
            try:
                width = float(width)
                if width <= 0:
                    raise ValueError()
            except ValueError:
                raise ValidationError('width', 'Positive FOV width expected')
        if height is not None:
            try:
                height = float(height)
                if height <= 0:
                    raise ValueError()
            except ValueError:
                raise ValidationError('height', 'Positive FOV height expected')
        if width is None:
            width = height
        elif height is None:
            height = width

        # noinspection PyProtectedMember
        if survey not in SkyView._valid_surveys:
            # Unknown survey
            return [], None

        if object is None:
            # Convert FOV center coordinates to standard form
            # noinspection PyUnresolvedReferences
            object = '{},{}'.format(ra_hours * 15, dec_degs)

        # Query SkyView; zero or one result is expected
        # noinspection PyBroadException
        try:
            kwargs = self._get_query_args(survey, width, height)
            kwargs.pop('show_progress')
            res = SkyView.get_image_list(object, **kwargs)
        except Exception:
            return [], None
        if not res:
            return [], None
        return [self._get_asset(survey, object, width, height)], None