diff --git a/CHANGES.rst b/CHANGES.rst index 1d926ebbea..630ba53092 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -43,6 +43,34 @@ esa.jwst - Add download_files_from_program method to get all products by program id [#3073] +mocserver +^^^^^^^^^ + +- Switch to https instead of http for the default url (allows pyodide to use the module) [#3139] + +- Add ``TimeMOC`` and ``STMOC`` as possible entries in ``MOCServer.query_region`` to + allow temporal and space-time searches [#3139] + +- ``return_moc`` now allows to ask for a Time-MOC or a Space-Time MOC rather than only + Space-MOCs [#3139] + +- Fix query by MOC that would write a file ``moc.fits`` where the method was executed + in overwriting mode (potentially deleting data if there was a conflicting file) [#3139] + +- Returned tables now have a default list of fields instead of the > 130 columns returned + previously. The full list of fields can be displayed with the new method + ``MOCServer.list_fields`` [#3139] + +- Add ``casesensitive`` parameter in the queries (previously, this was hardcoded + to ``True``) [#3139] + +- Add ``spacesys`` parameter to the queries to allow to filter on the different bodies + or frames. The list of available space systems can be printed with the new method + ``MOCServer.list_spacesys`` [#3139] + +- Add ``query_hips`` method, which is convenient to filter only Hierarchical progressive + surveys [#3139] + mpc ^^^ diff --git a/astroquery/mocserver/__init__.py b/astroquery/mocserver/__init__.py index 2030fd2821..95efa11a0c 100644 --- a/astroquery/mocserver/__init__.py +++ b/astroquery/mocserver/__init__.py @@ -1,7 +1,6 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -""" -CDS MOCServer Query Tool ------------------------- +"""CDS MOCServer Query Tool. +---------------------------- :Author: Matthieu Baumann (matthieu.baumann@astro.unistra.fr) @@ -13,8 +12,9 @@ Note: If the access to MOCs with the MOCServer tool was helpful for your research, the following acknowledgment would be appreciated:: - This research has made use of the MOCServer, a tool developed at CDS, Strasbourg, France aiming at retrieving - MOCs/meta-data from known data-sets. MOC is an IVOA standard described in the following paper : + This research has made use of the MOCServer, a tool developed at CDS, Strasbourg, + France aiming at retrieving MOCs/meta-data from known data-sets. MOC is an IVOA + standard described in : http://www.ivoa.net/documents/MOC/20140602/REC-MOC-1.0-20140602.pdf """ @@ -24,12 +24,11 @@ class Conf(_config.ConfigNamespace): - """ - Configuration parameters for ``astroquery.template_module``. - """ + """Configuration parameters for ``astroquery.template_module``.""" server = _config.ConfigItem( [ + "https://alasky.unistra.fr/MocServer/query", "http://alasky.unistra.fr/MocServer/query", "http://alaskybis.unistra.fr/MocServer/query", ], @@ -40,6 +39,16 @@ class Conf(_config.ConfigNamespace): 30, "Time limit for connecting to template_module server." ) + default_fields = [ + "ID", + "obs_title", + "obs_description", + "nb_rows", + "obs_regime", + "bib_reference", + "dataproduct_type", + ] + conf = Conf() diff --git a/astroquery/mocserver/core.py b/astroquery/mocserver/core.py index 8d45a8d4d8..ccab2a98ca 100644 --- a/astroquery/mocserver/core.py +++ b/astroquery/mocserver/core.py @@ -1,345 +1,688 @@ - # Licensed under a 3-clause BSD style license - see LICENSE.rst from ..query import BaseQuery from ..utils import commons -from ..utils import async_to_sync from . import conf -import os -from ast import literal_eval from copy import copy +from tempfile import NamedTemporaryFile from astropy import units as u from astropy.table import Table try: - from mocpy import MOC -except ImportError: - print("Could not import mocpy, which is a requirement for the MOC server service." - "Please refer to https://cds-astro.github.io/mocpy/install.html for how to install it.") - -try: - from regions import CircleSkyRegion, PolygonSkyRegion + from mocpy import MOC, TimeMOC, STMOC except ImportError: - print("Could not import astropy-regions, which is a requirement for the CDS service." - "Please refer to http://astropy-regions.readthedocs.io/en/latest/installation.html for how to install it.") + print("'mocpy' is a mandatory dependency for MOCServer. You can install " + "it with 'pip install mocpy'.") -__all__ = ['MOCServerClass', 'MOCServer'] +__all__ = ["MOCServerClass", "MOCServer"] -@async_to_sync class MOCServerClass(BaseQuery): - """ - Query the `CDS MOCServer `_ - - The `CDS MOCServer `_ allows the user to retrieve all the data sets (with - their meta-data) having sources in a specific region. This region can be a `regions.CircleSkyRegion`, a - `regions.PolygonSkyRegion` or a `mocpy.MOC` object. - - This package implements two methods: - - * :meth:`~astroquery.mocserver.MOCServerClass.query_region` retrieving data-sets - (their associated MOCs and meta-data) having sources in a given region. - * :meth:`~astroquery.mocserver.MOCServerClass.find_datasets` retrieving data-sets - (their associated MOCs and meta-data) based on the values of their meta-data. + """Query the `CDS MOCServer `_. + The `CDS MOCServer `_ allows the user + to retrieve all the datasets (with their meta-data) having sources in a specific + space-time region. This region can be a `regions.CircleSkyRegion`, a + `regions.PolygonSkyRegion`, a `mocpy.MOC`, a `mocpy.TimeMOC`, or a `mocpy.STMOC` + object. """ + URL = conf.server TIMEOUT = conf.timeout + DEFAULT_FIELDS = conf.default_fields def __init__(self): super().__init__() - self.path_moc_file = None self.return_moc = False - def query_region(self, *, region=None, get_query_payload=False, verbose=False, **kwargs): - """ - Query the `CDS MOCServer `_ with a region. - - Can be a `regions.CircleSkyRegion`, `regions.PolygonSkyRegion` or `mocpy.MOC` object. Returns the data-sets - having at least one source in the region. + def query_region( + self, region=None, + *, + meta_data=None, + intersect="overlaps", + return_moc=None, + max_norder=None, + fields=None, + max_rec=None, + casesensitive=False, + spacesys=None, + get_query_payload=False, + verbose=False, + cache=True, + ): + """Query the MOC Server. Parameters ---------- - region : `regions.CircleSkyRegion`, `regions.PolygonSkyRegion` or `mocpy.MOC` - The region to query the MOCServer with. - Can be one of the following types: - - * ``regions.CircleSkyRegion`` : defines an astropy cone region. - * ``regions.PolygonSkyRegion`` : defines an astropy polygon region. - * ``mocpy.moc.MOC`` : defines a MOC from the MOCPy library. See the `MOCPy's documentation - `__ for how to instantiate a MOC object. - + region : `regions.CircleSkyRegion`, `regions.PolygonSkyRegion`, `mocpy.MOC`, + `mocpy.TimeMOC`, or `mocpy.STMOC` + The region to query the MOCServer with. Note that this can also be a + space-time region with the Time-MOCs and Space-Time-MOCs. + Defaults to None, which means that the search will be on the whole sky. + meta_data : str + Algebraic expression to select the datasets. + Examples of expressions can be found `on the mocserver's examples page + `_. + Example: "ID=*HST*" will return datasets with HST in their ID column. The + star means any character. + casesensitive : Bool, optional + Whether the search should take the case into account. By default, False. + fields : [str], optional + Specifies which columns to retrieve. Defaults to a pre-defined subset of + fields. The complete list of fields can be obtained with `list_fields`. + spacesys: str, optional + This is the space system on which the coordinates are expressed. Can take + the values ``C`` (for the sky), ``mars``, ``moon``... The extended list can + be printed with `list_spacesys`. Default is None, meaning that the results + will have mixed frames. intersect : str, optional - This parameter can take only three different values: + This parameter can take three different values: + + - ``overlaps`` (default) select datasets overlapping the region + - ``covers`` returned datasets are covering the region. + - ``encloses`` returned datasets are enclosing the region. - - ``overlaps`` (default). Returned data-sets are those overlapping the MOC region. - - ``covers``. Returned data-sets are those covering the MOC region. - - ``encloses``. Returned data-sets are those enclosing the MOC region. max_rec : int, optional Maximum number of data-sets to return. By default, there is no upper limit. return_moc : bool, optional - Specifies if we want a `mocpy.MOC` object in return. This MOC corresponds to the union - of the MOCs of all the matching data-sets. By default it is set to False and - :meth:`~astroquery.mocserver.MOCServerClass.query_region` returns an `astropy.table.Table` object. + Specifies whether the output should be a `mocpy.MOC`. The returned MOC is the + union of the MOCs of all the matching datasets. By default it is False and + this method returns a `astropy.table.Table` object. max_norder : int, optional - Has sense only if ``return_moc`` is set to True. Specifies the maximum precision order of the returned MOC. - fields : [str], optional - Has sense only if ``return_moc`` is set to False. Specifies which meta data to retrieve. The returned - `astropy.table.Table` table will only contain the column names given in ``fields``. - - Specifying the fields we want to retrieve allows the request to be faster because of the reduced chunk of - data moving from the MOCServer to the client. - - Some meta-data as ``obs_collection`` or ``data_ucd`` do not keep a constant type throughout all the - MOCServer's data-sets and this lead to problems because `astropy.table.Table` supposes values in a column - to have an unique type. When we encounter this problem for a specific meta-data, we remove its corresponding - column from the returned astropy table. - meta_data : str, optional - Algebraic expression on meta-data for filtering the data-sets at the server side. - Examples of meta data expressions: - - * Retrieve all the Hubble surveys: "ID=*HST*" - * Provides the records of HiPS distributed simultaneously by saada and alasky http server: - "(hips_service_url*=http://saada*)&&(hips_service_url*=http://alasky.*)" - - More example of expressions can be found following this `link - `_ (especially see the urls). + If ``return_moc`` is set to True, this fixes the maximum precision order + of the returned MOC. For one dimensional MOCs (Space-MOCs and Time-MOCs), + the order is given as an integer. For Space-Time MOCs, the order should be a + string with the space and time orders. + Example: 's3 t45' get_query_payload : bool, optional - If True, returns a dictionary of the query payload instead of the parsed response. + If True, returns a dictionary of the query payload instead of the response. verbose : bool, optional + Whether to show warnings. Defaults to False. + cache: bool, optional + Whether the response should be cached. Returns ------- - response : `astropy.table.Table` or `mocpy.MOC` - By default an astropy table of the data-sets matching the query. If ``return_moc`` is set to True, it gives - a MOC object corresponding to the union of the MOCs from all the retrieved data-sets. + response : `astropy.table.Table`, `mocpy.MOC`, `mocpy.TimeMOC`, or `mocpy.STMOC` + By default, returns a table with the datasets matching the query. + If ``return_moc`` is set to True, it gives a MOC object corresponding to the + union of the MOCs from all the retrieved data-sets. + """ - response = self.query_region_async(get_query_payload=get_query_payload, region=region, **kwargs) + response = self.query_async( + meta_data=meta_data, + region=region, + intersect=intersect, + return_moc=return_moc, + max_norder=max_norder, + fields=fields, + max_rec=max_rec, + casesensitive=casesensitive, + spacesys=spacesys, + get_query_payload=get_query_payload, + cache=cache, + ) if get_query_payload: return response + return _parse_result(response, verbose=verbose, return_moc=return_moc) + + def query_hips( + self, + *, + meta_data=None, + region=None, + intersect="overlaps", + return_moc=None, + max_norder=None, + fields=None, + max_rec=None, + casesensitive=False, + spacesys=None, + get_query_payload=False, + verbose=False, + cache=True, + ): + """Query the MOCServer for HiPS surveys. + + Parameters + ---------- + meta_data : str + Algebraic expression to select the datasets. + Examples of expressions can be found `on the mocserver's examples page + `_. + Example: "ID=*HST*" will return datasets with HST in their ID column. The + star means any character. + casesensitive : Bool, optional + Wheter the search should take the case into account. By default, False. + fields : [str], optional + Specifies which columns to retrieve. Defaults to a pre-defined subset of + fields. The complete list of fields can be obtained with `list_fields`. + spacesys: str, optional + This is the space system on which the coordinates are expressed. Can take + the values ``C`` (for the sky), ``mars``, ``moon``... The extended list can + be printed with `list_spacesys`. Default is None, meaning that the results + will have mixed frames. + region : `regions.CircleSkyRegion`, `regions.PolygonSkyRegion`, `mocpy.MOC`, + `mocpy.TimeMOC`, or `mocpy.STMOC` + The region to query the MOCServer with. Note that this can also be a + space-time region with the Time-MOCs and Space-Time-MOCs. + intersect : str, optional + This parameter can take three different values: + + - ``overlaps`` (default) select datasets overlapping the region + - ``covers`` returned datasets are covering the region. + - ``encloses`` returned datasets are enclosing the region. - result = self._parse_result(response, verbose=verbose) + max_rec : int, optional + Maximum number of data-sets to return. By default, there is no upper limit. + return_moc : bool, optional + Specifies whether the output should be a `mocpy.MOC`. The returned MOC is the + union of the MOCs of all the matching datasets. By default it is False and + this method returns a `astropy.table.Table` object. + max_norder : int, optional + If ``return_moc`` is set to True, this fixes the maximum precision order + of the returned MOC. For one dimensional MOCs (Space-MOCs and Time-MOCs), + the order is given as an integer. For Space-Time MOCs, the order should be a + string with the space and time orders. + Example: 's3 t45' + get_query_payload : bool, optional + If True, returns a dictionary of the query payload instead of the response. + verbose : bool, optional + Whether to show warnings. Defaults to False. + cache: bool, optional + Whether the response should be cached. - return result + Returns + ------- + response : `astropy.table.Table`, `mocpy.MOC`, `mocpy.TimeMOC`, or `mocpy.STMOC` + By default, returns a table with the datasets matching the query. + If ``return_moc`` is set to True, it gives a MOC object corresponding to the + union of the MOCs from all the retrieved data-sets. - def find_datasets(self, meta_data, *, get_query_payload=False, verbose=False, **kwargs): """ - Query the `CDS MOCServer `_ to retrieve the data-sets based on their - meta data values. This method does not need any region argument but it requires an expression on the meta datas. + if meta_data: + meta_data = f"({meta_data})&&hips_frame=*" + else: + meta_data = "hips_frame=*" + return self.query_region( + meta_data=meta_data, + region=region, + intersect=intersect, + return_moc=return_moc, + max_norder=max_norder, + fields=fields, + max_rec=max_rec, + casesensitive=casesensitive, + spacesys=spacesys, + get_query_payload=get_query_payload, + verbose=verbose, + cache=cache, + ) + + def find_datasets( + self, meta_data, + *, + region=None, + intersect="overlaps", + return_moc=None, + max_norder=None, + fields=None, + max_rec=None, + casesensitive=False, + spacesys=None, + get_query_payload=False, + verbose=False, + cache=True, + ): + """Query the MOC Server. Parameters ---------- meta_data : str - Algebraic expression on meta-data for filtering the data-sets at the server side. - Examples of meta data expressions: + Algebraic expression to select the datasets. + Examples of expressions can be found `on the mocserver's examples page + `_. + Example: "ID=*HST*" will return datasets with HST in their ID column. The + star means any character. + casesensitive : Bool, optional + Whether the search should take the case into account. By default, False. + fields : [str], optional + Specifies which columns to retrieve. Defaults to a pre-defined subset of + fields. The complete list of fields can be obtained with `list_fields`. + spacesys: str, optional + This is the space system on which the coordinates are expressed. Can take + the values ``C`` (for the sky), ``mars``, ``moon``... The extended list can + be printed with `list_spacesys`. Default is None, meaning that the results + will have mixed frames. + region : `regions.CircleSkyRegion`, `regions.PolygonSkyRegion`, `mocpy.MOC`, + `mocpy.TimeMOC`, or `mocpy.STMOC` + The region to query the MOCServer with. Note that this can also be a + space-time region with the Time-MOCs and Space-Time-MOCs. + intersect : str, optional + This parameter can take three different values: - * Retrieve all the Hubble surveys: "ID=*HST*" - * Provides the records of HiPS distributed simultaneously by saada and alasky http server: - "(hips_service_url*=http://saada*)&&(hips_service_url*=http://alasky.*)" + - ``overlaps`` (default) select datasets overlapping the region + - ``covers`` returned datasets are covering the region. + - ``encloses`` returned datasets are enclosing the region. - More example of expressions can be found following this `link - `_ (especially see the urls). - fields : [str], optional - Has sense only if ``return_moc`` is set to False. Specifies which meta data to retrieve. The returned - `astropy.table.Table` table will only contain the column names given in ``fields``. - - Specifying the fields we want to retrieve allows the request to be faster because of the reduced chunk of - data moving from the MOCServer to the client. - - Some meta-data such as ``obs_collection`` or ``data_ucd`` do not keep a constant type throughout all the - MOCServer's data-sets and this lead to problems because `astropy.table.Table` supposes values in a column - to have an unique type. This case is not common: it is mainly linked to a typing error in the text files - describing the meta-data of the data-sets. When we encounter this for a specific meta-data, we link the - generic type ``object`` to the column. Therefore, keep in mind that ``object`` typed columns can contain - values of different types (e.g. lists and singletons or string and floats). max_rec : int, optional Maximum number of data-sets to return. By default, there is no upper limit. return_moc : bool, optional - Specifies if we want a `mocpy.MOC` object in return. This MOC corresponds to the union of the MOCs of all - the matching data-sets. By default it is set to False and - :meth:`~astroquery.mocserver.MOCServerClass.query_region` returns an `astropy.table.Table` object. + Specifies whether the output should be a `mocpy.MOC`. The returned MOC is the + union of the MOCs of all the matching datasets. By default it is False and + this method returns a `astropy.table.Table` object. max_norder : int, optional - Has sense only if ``return_moc`` is set to True. Specifies the maximum precision order of the returned MOC. + If ``return_moc`` is set to True, this fixes the maximum precision order + of the returned MOC. For one dimensional MOCs (Space-MOCs and Time-MOCs), + the order is given as an integer. For Space-Time MOCs, the order should be a + string with the space and time orders. + Example: 's3 t45' get_query_payload : bool, optional - If True, returns a dictionary of the query payload instead of the parsed response. + If True, returns a dictionary of the query payload instead of the response. verbose : bool, optional + Whether to show warnings. Defaults to False. + cache: bool, optional + Whether the response should be cached. Returns ------- - response : `astropy.table.Table` or `mocpy.MOC` - By default an astropy table of the data-sets matching the query. If ``return_moc`` is set to True, it gives - a MOC object corresponding to the union of the MOCs from all the retrieved data-sets. - """ - response = self.query_region_async(get_query_payload=get_query_payload, meta_data=meta_data, **kwargs) - if get_query_payload: - return response - - result = self._parse_result(response, verbose=verbose) + response : `astropy.table.Table`, `mocpy.MOC`, `mocpy.TimeMOC`, or `mocpy.STMOC` + By default, returns a table with the datasets matching the query. + If ``return_moc`` is set to True, it gives a MOC object corresponding to the + union of the MOCs from all the retrieved data-sets. - return result - - def query_region_async(self, *, get_query_payload=False, **kwargs): """ - Serves the same purpose as :meth:`~astroquery.mocserver.MOCServerClass.query_region` - but only returns the HTTP response rather than the parsed result. + return self.query_region( + meta_data=meta_data, + region=region, + intersect=intersect, + return_moc=return_moc, + max_norder=max_norder, + fields=fields, + max_rec=max_rec, + casesensitive=casesensitive, + spacesys=spacesys, + get_query_payload=get_query_payload, + verbose=verbose, + cache=cache, + ) + + def query_async( + self, + *, + region=None, + meta_data=None, + return_moc=None, + max_norder=None, + fields=None, + max_rec=None, + intersect="overlaps", + spacesys=None, + casesensitive=False, + get_query_payload=False, + cache=True, + ): + """Return the HTTP response rather than the parsed result. Parameters ---------- - get_query_payload : bool - If True, returns a dictionary of the query payload instead of the parsed response. - **kwargs - Arbitrary keyword arguments. + meta_data : str + Algebraic expression to select the datasets. + Examples of expressions can be found `on the mocserver's examples page + `_. + Example: "ID=*HST*" will return datasets with HST in their ID column. The + star means any character. + casesensitive : Bool, optional + Whether the search should take the case into account. By default, False. + fields : [str], optional + Specifies which columns to retrieve. Defaults to a pre-defined subset of + fields. The complete list of fields can be obtained with `list_fields`. + spacesys: str, optional + This is the space system on which the coordinates are expressed. Can take + the values ``C`` (for the sky), ``mars``, ``moon``... The extended list can + be printed with `list_spacesys`. Default is None, meaning that the results + will have mixed frames. + region : `regions.CircleSkyRegion`, `regions.PolygonSkyRegion`, `mocpy.MOC`, + `mocpy.TimeMOC`, or `mocpy.STMOC` + The region to query the MOCServer with. Note that this can also be a + space-time region with the Time-MOCs and Space-Time-MOCs. + intersect : str, optional + This parameter can take three different values: + + - ``overlaps`` (default) select datasets overlapping the region + - ``covers`` returned datasets are covering the region. + - ``encloses`` returned datasets are enclosing the region. + + max_rec : int, optional + Maximum number of data-sets to return. By default, there is no upper limit. + return_moc : bool, optional + Specifies whether the output should be a `mocpy.MOC`. The returned MOC is the + union of the MOCs of all the matching datasets. By default it is False and + this method returns a `astropy.table.Table` object. + max_norder : int, optional + If ``return_moc`` is set to True, this fixes the maximum precision order + of the returned MOC. For one dimensional MOCs (Space-MOCs and Time-MOCs), + the order is given as an integer. For Space-Time MOCs, the order should be a + string with the space and time orders. + Example: 's3 t45' + get_query_payload : bool, optional + If True, returns a dictionary of the query payload instead of the response. + verbose : bool, optional + cache: bool, optional + Whether the response should be cached. Returns ------- response : `~requests.Response`: - The HTTP response from the `CDS MOCServer `_. + The HTTP response from the + `CDS MOCServer `_. + """ - request_payload = self._args_to_payload(**kwargs) - if get_query_payload: - return request_payload + request_payload = _args_to_payload( + meta_data=meta_data, + return_moc=return_moc, + max_norder=max_norder, + fields=fields, + max_rec=max_rec, + region=region, + intersect=intersect, + spacesys=spacesys, + casesensitive=casesensitive, + default_fields=self.DEFAULT_FIELDS, + ) params_d = { - 'method': 'GET', - 'url': self.URL, - 'timeout': self.TIMEOUT, - 'data': kwargs.get('data', None), - 'cache': False, - 'params': request_payload, + "method": "GET", + "url": self.URL, + "timeout": self.TIMEOUT, + "cache": cache, + "params": request_payload, } - if not self.path_moc_file: - response = self._request(**params_d) - else: - # The user ask for querying on a MOC region. - with open(self.path_moc_file, 'rb') as f: - params_d.update({'files': {'moc': f.read()}}) - response = self._request(**params_d) + if region: + if get_query_payload: + return request_payload + if not isinstance(region, (MOC, TimeMOC, STMOC)): + return self._request(**params_d) + # MOCs have to be sent in a multipart request + with NamedTemporaryFile() as tmp_file: + region.save(tmp_file.name, overwrite=True, format="fits") - return response + params_d.update({"files": {"moc": tmp_file.read()}}) + return self._request(**params_d) - def _args_to_payload(self, **kwargs): - """ - Convert the keyword arguments to a payload. + if get_query_payload: + return request_payload + return self._request(**params_d) + + def list_fields(self, keyword=None, cache=True): + """List MOC Server fields. + + In the MOC Server, the fields are free. This means that anyone publishing there + can set a new field. This results in a long set of possible fields, that are + more or less frequent in the database. + This method allows to retrieve all fields currently existing, with their + occurrences and an example. Parameters ---------- - kwargs - Arbitrary keyword arguments. The same as those defined in the docstring of - :meth:`~astroquery.mocserver.MOCServerClass.query_object`. + keyword : str, optional + A keyword to filter the output for fields that have the keyword in their + name. This is not case-sensitive. + If you don't give a keyword, you will retrieve all existing fields. + cache: bool, optional + Whether the response should be cached. Returns ------- - request_payload : dict - The payload submitted to the MOC server. - """ - request_payload = dict() - intersect = kwargs.get('intersect', 'overlaps') - if intersect == 'encloses': - intersect = 'enclosed' - - request_payload.update({'intersect': intersect, - 'casesensitive': 'true', - 'fmt': 'json', - 'get': 'record', - }) - - # Region Type - if 'region' in kwargs: - region = kwargs['region'] - if isinstance(region, MOC): - self.path_moc_file = os.path.join(os.getcwd(), 'moc.fits') - if os.path.isfile(self.path_moc_file): # Silent overwrite - os.remove(self.path_moc_file) - region.save(self.path_moc_file, format="fits") - # add the moc region payload to the request payload - elif isinstance(region, CircleSkyRegion): - # add the cone region payload to the request payload - request_payload.update({ - 'DEC': str(region.center.dec.to(u.deg).value), - 'RA': str(region.center.ra.to(u.deg).value), - 'SR': str(region.radius.to(u.deg).value), - }) - elif isinstance(region, PolygonSkyRegion): - # add the polygon region payload to the request payload - polygon_payload = "Polygon" - vertices = region.vertices - for i in range(len(vertices.ra)): - polygon_payload += ' ' + str(vertices.ra[i].to(u.deg).value) + \ - ' ' + str(vertices.dec[i].to(u.deg).value) - request_payload.update({'stc': polygon_payload}) - else: - if region is not None: - raise ValueError('`region` belongs to none of the following types: `regions.CircleSkyRegion`,' - '`regions.PolygonSkyRegion` or `mocpy.MOC`') - - if 'meta_data' in kwargs: - request_payload.update({'expr': kwargs['meta_data']}) - - if 'fields' in kwargs: - fields = kwargs['fields'] - field_l = list(fields) if not isinstance(fields, list) else copy(fields) - # The CDS MOC service responds badly to record queries which do not ask - # for the ID field. To prevent that, we add it to the list of requested fields - field_l.append('ID') - field_l = list(set(field_l)) - fields_str = str(field_l[0]) - for field in field_l[1:]: - fields_str += ', ' - fields_str += field - - request_payload.update({"fields": fields_str}) - - if 'max_rec' in kwargs: - max_rec = kwargs['max_rec'] - request_payload.update({'MAXREC': str(max_rec)}) - - self.return_moc = kwargs.get('return_moc', False) - if self.return_moc: - request_payload.update({'get': 'moc'}) - if 'max_norder' in kwargs: - request_payload.update({'order': kwargs['max_norder']}) - else: - request_payload.update({'order': 'max'}) - - return request_payload - - def _parse_result(self, response, *, verbose=False): + `~astropy.table.Table` + A table containing the field names, heir occurrence (expressed in number + of records), and an example for each field. + + Examples + -------- + >>> from astroquery.mocserver import MOCServer + >>> MOCServer.list_fields("publisher") # doctest: +REMOTE_DATA +IGNORE_OUTPUT + + field_name occurrence example + str27 int64 str70 + -------------- ---------- ------------------------- + publisher_id 32987 ivo://CDS + publisher_did 2871 ivo://nasa.heasarc/warps2 + hips_publisher 14 CDS + """ - Parsing of the response returned by the MOCServer. + fields_descriptions = dict(self.list_fields_async(cache=cache).json()[0]) + occurrences = [ + int(value.split("x")[0][1:]) for value in fields_descriptions.values() + ] + field_names = list(fields_descriptions.keys()) + examples = [value.split("ex: ")[-1] for value in fields_descriptions.values()] + list_fields = Table( + [field_names, occurrences, examples], + names=["field_name", "occurrence", "example"], + ) + list_fields.sort("occurrence", reverse=True) + if keyword: + return list_fields[ + [ + keyword.casefold() in name.casefold() + for name in list_fields["field_name"] + ] + ] + return list_fields + + def list_fields_async(self, cache=True): + """List MOC Server fields asynchronously. + + In the MOC Server, the fields are free. This means that anyone publishing there + can set a new field. This results in a long set of possible fields, that are + more or less frequent in the database. + This method allows to retrieve all fields currently existing, with their + occurrences and an example. Parameters ---------- - response : `~requests.Response` - The HTTP response returned by the MOCServer. - verbose : bool, optional - False by default. + keyword : str, optional + A keyword to filter the output for fields that have the keyword in their + name. This is not case-sensitive. + If you don't give a keyword, you will retrieve all existing fields. + cache: bool, optional + Whether the response should be cached. Returns ------- - result : `astropy.table.Table` or `mocpy.MOC` - By default an astropy table of the data-sets matching the query. If ``return_moc`` is set to True, it gives - a MOC object corresponding to the union of the MOCs from all the matched data-sets. + `~requests.models.Response` + """ - if not verbose: - commons.suppress_vo_warnings() + return self._request( + method="GET", + url=self.URL, + timeout=self.TIMEOUT, + cache=cache, + params={"get": "example", "fmt": "json"}, + ) - result = response.json() + def list_spacesys(self): + """Return the list of "spacesys" currently available in the MOC Server. - if not self.return_moc: - # return a table with the meta-data, we cast the string values for convenience - result = [{key: _cast_to_float(value) for key, value in row.items()} for row in result] - return Table(rows=result) + This list may be enriched later, as new datasets are added into the MOC Server. + + Returns + ------- + list + The list of spacesys currently available in the MOC Server + + """ + frames = list(set(self.query_region(meta_data="hips_frame=*", + fields=["ID", "hips_frame"], + spacesys=None)["hips_frame"])) + # `C` is a special case that corresponds to both equatorial and galactic frames + frames.append("C") + frames.sort() + return frames + + +def _args_to_payload( + *, + meta_data=None, + return_moc=None, + max_norder=None, + fields=None, + max_rec=None, + region=None, + intersect="overlaps", + spacesys=None, + casesensitive=False, + default_fields=None, +): + """Convert the parameters of `query_region` and `find_datasets` into a payload. + + Returns + ------- + dict + The payload that will be submitted to the MOC server. - # return a `mocpy.MOC` object. See https://github.com/cds-astro/mocpy and the MOCPy's doc - return MOC.from_json(result) - -def _cast_to_float(value): """ - Cast ``value`` to a float if possible. + request_payload = { + "casesensitive": str(casesensitive).casefold(), + "fmt": "json", + "get": "record", + "fields": _get_fields(fields, default_fields), + "intersect": intersect.replace("encloses", "enclosed"), + "spacesys": spacesys, + } + + if region and not isinstance(region, (MOC, STMOC, TimeMOC)): + try: + from regions import CircleSkyRegion, PolygonSkyRegion + except ImportError as err: + raise ImportError( + "The module 'regions' is mandatory to use " + "'query_region' without a MOC. Install it with " + "'pip install regions'" + ) from err + if isinstance(region, CircleSkyRegion): + # add the cone region payload to the request payload + request_payload.update( + { + "DEC": str(region.center.dec.to(u.deg).value), + "RA": str(region.center.ra.to(u.deg).value), + "SR": str(region.radius.to(u.deg).value), + } + ) + elif isinstance(region, PolygonSkyRegion): + # add the polygon region payload to the request payload + polygon_payload = "Polygon" + for point in region.vertices: + polygon_payload += ( + f" {point.ra.to(u.deg).value} {point.dec.to(u.deg).value}" + ) + print(polygon_payload) + request_payload.update({"stc": polygon_payload}) + # the MOCs have to be sent through the multipart and not through the payload + else: + # not of any accepted type + raise ValueError( + "'region' should be of type: 'regions.CircleSkyRegion'," + " 'regions.PolygonSkyRegion', 'mocpy.MOC', 'mocpy.TimeMOC'" + f" or 'mocpy.STMOC', but is of type '{type(region)}'." + ) + + if meta_data: + request_payload.update({"expr": meta_data}) + + if max_rec: + request_payload.update({"MAXREC": str(max_rec)}) + + if return_moc: + if return_moc is True: + # this is for legacy reasons return_moc used to be a boolean when the MOC + # server could only return space MOCs. + return_moc = "moc" + request_payload.update({"get": return_moc}) + request_payload.update({"fmt": "ascii"}) + if max_norder: + request_payload.update({"order": max_norder}) + else: + request_payload.update({"order": "max"}) + return request_payload + + +def _get_fields(fields, default_fields): + """Get the list of fields to be queried. + + Defaults to the list defined in conf if fields is None. + + Parameters + ---------- + fields : list[str] or str + The list of columns to be returned. + default_fields : list[str] + The default list of fields. + + """ + if fields: + if isinstance(fields, str): + fields = [fields] + if "ID" not in fields: + # ID has to be included for the server to work correctly + fields.append("ID") + fields = list(fields) if not isinstance(fields, list) else copy(fields) + else: + fields = default_fields + return ", ".join(fields) + + +def _parse_result(response, *, verbose=False, return_moc): + """Parse the response returned by the MOCServer. + + Parameters + ---------- + response : `~requests.Response` + The HTTP response returned by the MOCServer. + verbose : bool, optional + False by default. + return_moc : str or Bool + Whether the result is a MOC or a Table. + + Returns + ------- + `astropy.table.Table`, `~mocpy.MOC`, `~mocpy.STMOC`, `~mocpy.TimeMOC` + This returns a table if ``return_moc`` is not specified. Otherwise, + a MOC of the requested kind. + + """ + if not verbose: + commons.suppress_vo_warnings() + + if return_moc: + result = response.text + # return_moc==True is there to support the version when there was no choice in + # in the MOC in output and the MOC server would only be able to return SMOCs + if return_moc == "moc" or return_moc == "smoc" or return_moc is True: + return MOC.from_str(result) + if return_moc == "tmoc": + return TimeMOC.from_str(result) + if return_moc == "stmoc": + return STMOC.from_str(result) + raise ValueError( + "'return_moc' can only take the values 'moc', 'tmoc', 'smoc'," + f"or 'stmoc'. Got '{return_moc}'." + ) + # return a table with the meta-data, we cast the string values for convenience + result = response.json() + result = [ + {key: _cast_to_float(value) for key, value in row.items()} for row in result + ] + return Table(rows=result) + + +def _cast_to_float(value): + """Cast ``value`` to a float if possible. Parameters ---------- @@ -348,12 +691,14 @@ def _cast_to_float(value): Returns ------- - value : float or str - A float if it can be casted so otherwise the initial string. + float or str + A float if it can be converted to a float. Otherwise the initial string. + """ try: return float(value) except (ValueError, TypeError): return value + MOCServer = MOCServerClass() diff --git a/astroquery/mocserver/tests/data/hips_frames.vot b/astroquery/mocserver/tests/data/hips_frames.vot new file mode 100644 index 0000000000..a30f1945f7 --- /dev/null +++ b/astroquery/mocserver/tests/data/hips_frames.vot @@ -0,0 +1,314 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
galactic
galactic
equatorial
equatorial
galactic
equatorial
sun
equatorial
equatorial
venus
galactic
triton
galactic
galactic
galactic
equatorial
equatorial
equatorial
galactic
galactic
galactic
galactic
equatorial
galactic
galactic
galactic
galactic
galactic
galactic
galactic
equatorial
equatorial
equatorial
galactic
galactic
equatorial
equatorial
equatorial
equatorial
equatorial
equatorial
equatorial
galactic
galactic
equatorial
galactic
equatorial
galactic
galactic
equatorial
galactic
galactic
galactic
galactic
equatorial
galactic
galactic
galactic
galactic
galactic
galactic
galactic
galactic
galactic
equatorial
equatorial
equatorial
equatorial
equatorial
equatorial
equatorial
equatorial
galactic
galactic
galactic
equatorial
equatorial
equatorial
galactic
galactic
galactic
galactic
galactic
galactic
equatorial
galactic
equatorial
galactic
galactic
galactic
equatorial
neptune
equatorial
equatorial
equatorial
equatorial
galactic
equatorial
galactic
moon
+ + diff --git a/astroquery/mocserver/tests/data/hips_from_saada_alasky.json b/astroquery/mocserver/tests/data/hips_from_saada_alasky.json deleted file mode 100644 index 0c19110752..0000000000 --- a/astroquery/mocserver/tests/data/hips_from_saada_alasky.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"ID": "xcatdb/P/XMM/PN/color"}, - {"ID": "xcatdb/P/XMM/PN/eb2"}, - {"ID": "xcatdb/P/XMM/PN/eb3"}, - {"ID": "xcatdb/P/XMM/PN/eb4"} -] diff --git a/astroquery/mocserver/tests/data/list_fields.json b/astroquery/mocserver/tests/data/list_fields.json new file mode 100644 index 0000000000..6b3b178aee --- /dev/null +++ b/astroquery/mocserver/tests/data/list_fields.json @@ -0,0 +1 @@ +{"ID": "(37291x) ex: CDS/J/AJ/165/248/table3", "publisher_id": "(33146x) ex: ivo://CDS", "obs_id": "(33121x) ex: J/AJ/165/248/table3", "obs_title": "(37274x) ex: COSMOS2020; 230 quiescent galaxies at 3=10.040 AladinDesktop>=11.125", "hips_rgb_red": "(56x) ex: XMM EPIC (RED) [1.0E-6 NaN 0.003 Log]", "hips_rgb_green": "(46x) ex: XMM EPIC (GREEN) [1.0E-6 NaN 0.003 Log]", "hips_rgb_blue": "(56x) ex: XMM EPIC (BLUE) [1.0E-6 NaN 0.003 Log]", "obs_superseded_by": "(262x) ex: V/145", "bib_reference_url": "(448x) ex: http://cdsads.u-strasbg.fr/abs/1996ASPC..101...88L", "client_sort_key": "(193x) ex: 03-01-03a", "hips_master_url": "(61x) ex: https://hips.astron.nl/ASTRON/P/lotss_dr1_high/", "hips_cat_nrows": "(29x) ex: 862", "data_bunit": "(10x) ex: sr-1", "prov_did": "(41x) ex: ivo://CDS/I/355/gaiadr3", "glutag": "(12x) ex: VizieRGaiaCustom", "hips_publisher": "(14x) ex: CDS", "hips_cube_depth": "(24x) ex: 2177", "hips_cube_firstframe": "(24x) ex: 1088", "addendum_id": "(14x) ex: APPEND/P/1678101097", "o_unit": "(2x) ex: m", "o_ucd": "(2x) ex: pos.bodyrc.alt", "creator": "(43x) ex: ESA (ESDC & INTEGRAL SOC)", "data_cube_crpix3": "(18x) ex: 0", "data_cube_crval3": "(18x) ex: 1.79934", "data_cube_cdelt3": "(18x) ex: 0.0252101", "data_cube_cunit3": "(1x) ex: 'pc-LOG'", "moc_release_date": "(4x) ex: 2015-02-25T11:51Z", "obs_acknowledgement": "(1x) ex: Centre de Donnees astronomique de Strasbourg", "client_link": "(4x) ex: CDS/P/DM/simbad-biblio/otypes/Galaxy maps by object-type", "client_tap_mainlist": "(6x) ex: true", "hips_skyval_method": "(34x) ex: SKYVAL", "hips_skyval_value": "(34x) ex: -0.5 100.0 -357.66149139404297 1421.6846084594727", "hread": "(1x) ex: 8 partitioning=4096", "data_cube_bunit3": "(16x) ex: null", "hips_skyval": "(25x) ex: none", "obs_ack_url": "(9x) ex: https://www.nasa.gov/webbfirstimages", "obs_progenitor": "(1x) ex: CADC", "order": "(3x) ex: 5", "obs_provenance": "(2x) ex: NOAO", "hhips_builder": "(2x) ex: Aladin/HipsGen v12.060", "hips_data_minmax": "(4x) ex: -57430 90620", "#client_category": "(1x) ex: Problematic", "obs_descrition_url": "(1x) ex: http://l2db.selene.darts.isas.jaxa.jp/index.html.en", "cs_glutag": "(1x) ex: SkyBoT.IMCCE", "ohips_frame": "(1x) ex: equatorial", "hips_bunit": "(2x) ex: (1/2.04142)MJy/sr", "hips_glu_tag": "(1x) ex: P-GLIMPSE360.hpx", "hips_lon_asc": "(1x) ex: true", "obs_copyrigh_url": "(1x) ex: http://amundsen.astro.swarthmore.edu/SHASSA/index.html", "HiPSBuilder": "(1x) ex: cds.hips.cat.standalone.v0.1", "processingDate": "(1x) ex: 2016-04-01T13:18Z", "isCatalog": "(1x) ex: true", "nbSources": "(1x) ex: 623604", "hips_pixel_function": "(1x) ex: asinh"} \ No newline at end of file diff --git a/astroquery/mocserver/tests/data/properties.json b/astroquery/mocserver/tests/data/properties.json deleted file mode 100644 index 7670c3e990..0000000000 --- a/astroquery/mocserver/tests/data/properties.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - {"ID": "CDS/J/ApJ/749/10/SDSS-obs"}, - {"ID": "CDS/P/HLA/SDSSg"}, - {"ID": "CDS/P/HLA/SDSSr"}, - {"ID": "CDS/P/HLA/SDSSz"}, - {"ID": "CDS/P/HST/SDSSg"}, - {"ID": "CDS/P/HST/SDSSr"}, - {"ID": "CDS/P/HST/SDSSz"} -] diff --git a/astroquery/mocserver/tests/setup_package.py b/astroquery/mocserver/tests/setup_package.py index 89f6c4bf6a..b5b7e838a4 100644 --- a/astroquery/mocserver/tests/setup_package.py +++ b/astroquery/mocserver/tests/setup_package.py @@ -1,7 +1,11 @@ -import os +from pathlib import Path def get_package_data(): - paths_test = [os.path.join("data", "*.json"), os.path.join("data", "*.fits")] + paths_test = [ + str(Path("data") / "hips_frames.vot"), + str(Path("data") / "list_fields.json"), + str(Path("data") / "moc.fits"), + ] return {"astroquery.mocserver.tests": paths_test} diff --git a/astroquery/mocserver/tests/test_mocserver.py b/astroquery/mocserver/tests/test_mocserver.py index d724bd563f..fda74f989c 100644 --- a/astroquery/mocserver/tests/test_mocserver.py +++ b/astroquery/mocserver/tests/test_mocserver.py @@ -1,154 +1,172 @@ - # Licensed under a 3-clause BSD style license - see LICENSE.rst +import json +from pathlib import Path + import pytest -import os -import requests from astropy import coordinates +from astropy.io.votable import parse_single_table from astropy.table import Table -from ..core import MOCServer -from astroquery.utils.mocks import MockResponse +try: + from mocpy import MOC, STMOC, TimeMOC, FrequencyMOC + HAS_MOCPY = True +except ImportError: + HAS_MOCPY = False +try: + from regions import CircleSkyRegion, PolygonSkyRegion # noqa: E402 + HAS_REGIONS = True +except ImportError: + HAS_REGIONS = False + +from ... import mocserver +from ..core import MOCServer, _parse_result, _cast_to_float + + +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +@pytest.mark.skipif(not HAS_REGIONS, reason="regions is required") +def test_polygon_spatial_request(): + polygon_region = PolygonSkyRegion( + coordinates.SkyCoord( + [57.376, 56.391, 56.025, 56.616], + [24.053, 24.622, 24.049, 24.291], + frame="icrs", + unit="deg", + ) + ) + request_payload = MOCServer.query_region( + region=polygon_region, intersect="overlaps", get_query_payload=True + ) + print(request_payload) + assert request_payload["stc"] == ( + "Polygon 57.376 24.053 56.391 24.622 56.025 24.049 56.616 24.291" + ) -pytest.importorskip("mocpy") -pytest.importorskip("regions") +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +@pytest.mark.skipif(not HAS_REGIONS, reason="regions is required") +def test_cone_search_spatial_request(): + ra = 10.8 + dec = 6.5 + radius = 0.5 + center = coordinates.SkyCoord(ra, dec, unit="deg") + cone_region = CircleSkyRegion( + center=center, radius=coordinates.Angle(radius, unit="deg") + ) + request_payload = MOCServer.query_region( + region=cone_region, get_query_payload=True, intersect="overlaps" + ) + assert request_payload["DEC"] == str(dec) + assert request_payload["RA"] == str(ra) + assert request_payload["SR"] == str(radius) -from regions import CircleSkyRegion, PolygonSkyRegion # noqa: E402 +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +def test_regions_provided_as_mocs(monkeypatch): + # FrequencyMOCs are not supported yet, they should raise an error, along with + # any other unsupported type + with pytest.raises(ValueError, match="'region' should be of type: *"): + MOCServer.query_region(region=FrequencyMOC.from_str("5/0"), + get_query_payload=True) + # patching _request -DATA_FILES = { - "PROPERTIES_SEARCH": "properties.json", - "HIPS_FROM_SAADA_AND_ALASKY": "hips_from_saada_alasky.json", -} + def mockreturn(**kwargs): + return kwargs + monkeypatch.setattr(MOCServer, "_request", mockreturn) + # looping on accepted MOC flavors + for moc in [ + MOC.from_str("0/0-11"), + TimeMOC.from_str("0/0-1"), + STMOC.from_str("t0/0-1 s0/0-11"), + ]: + tempfile_moc = MOCServer.query_async(region=moc)["files"]["moc"] + assert tempfile_moc.startswith(b"SIMPLE = T") -@pytest.fixture -def patch_get(request): - mp = request.getfixturevalue("monkeypatch") - - mp.setattr(requests.Session, "request", get_mockreturn) - return mp - - -def get_mockreturn( - self, - method, - url, - data=None, - timeout=10, - files=None, - params=None, - headers=None, - **kwargs -): - filename = data_path(DATA_FILES[data]) - with open(filename, "rb") as infile: - content = infile.read() - return MockResponse(content) - - -def data_path(filename): - data_dir = os.path.join(os.path.dirname(__file__), "data") - return os.path.join(data_dir, filename) - - -"""List of all the constrain we want to test""" - - -# SPATIAL CONSTRAINTS DEFINITIONS -polygon1 = coordinates.SkyCoord( - [57.376, 56.391, 56.025, 56.616], - [24.053, 24.622, 24.049, 24.291], - frame="icrs", - unit="deg", -) -polygon2 = coordinates.SkyCoord( - [58.376, 53.391, 56.025, 54.616], - [24.053, 25.622, 22.049, 27.291], - frame="icrs", - unit="deg", -) - -# PROPERTY CONSTRAINTS DEFINITIONS -meta_data_ex = "ID = *SDSS* && moc_sky_fraction<=0.01" -meta_data_hips_from_saada_alasky = ( - "(hips_service_url*=http://saada*) && (hips_service_url*=http://alasky.*)" -) -""" -Combination of one spatial with a property constrain - -Each tuple(spatial, property) characterizes a specific query and is tested -with regards to the true results stored in a file located in the data directory - -""" - - -@pytest.mark.parametrize( - "datafile", ["PROPERTIES_SEARCH", "HIPS_FROM_SAADA_AND_ALASKY"] -) -def test_request_results(patch_get, datafile): - """ - Compare the request result obtained with the astroquery.Mocserver API - - with the one obtained on the http://alasky.unistra.fr/MocServer/query - """ - results = MOCServer.query_region( - get_query_payload=False, verbose=True, data=datafile - ) - assert isinstance(results, Table) +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +def test_query_hips(): + # no meta + payload = MOCServer.query_hips(get_query_payload=True) + assert payload["expr"] == "hips_frame=*" + # with meta + payload = MOCServer.query_hips(meta_data="TEST", get_query_payload=True) + assert payload["expr"] == "(TEST)&&hips_frame=*" -""" -Spatial Constrains requests -We test a polygon/cone/moc search and ensure the -request param 'intersect' is correct +# ----------- +# List fields +# ----------- -""" +@pytest.fixture +def _mock_list_fields(monkeypatch): + """Avoid a request to get the list of fields in the mocserver.""" + + # This response changes with time. To regenerate it, do: + # >>> from astroquery.mocserver import MOCServer + # >>> import json + # >>> response = MOCServer.list_fields_async() + # >>> with open("list_fields.json", "w") as f: + # ... json.dump(dict(response.json()[0])) + class MockedListFields: + def json(self): + with open(Path(__file__).parent / "data" / "list_fields.json", "r") as f: + return [json.load(f)] + + monkeypatch.setattr( + mocserver.MOCServerClass, + "list_fields_async", + lambda self, cache: MockedListFields(), + ) -@pytest.mark.parametrize( - "RA, DEC, RADIUS", [(10.8, 6.5, 0.5), (25.6, -23.2, 1.1), (150.6, 45.1, 1.5)] -) -def test_cone_search_spatial_request(RA, DEC, RADIUS): - center = coordinates.SkyCoord(ra=RA, dec=DEC, unit="deg") - radius = coordinates.Angle(RADIUS, unit="deg") - cone_region = CircleSkyRegion(center=center, radius=radius) - request_payload = MOCServer.query_region( - region=cone_region, get_query_payload=True, intersect="overlaps" - ) +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +@pytest.mark.usefixtures("_mock_list_fields") +def test_list_fields(): + fields = MOCServer.list_fields("id") + assert "ID" in fields["field_name"] - assert ( - (request_payload["DEC"] == str(DEC)) - and (request_payload["RA"] == str(RA)) - and (request_payload["SR"] == str(RADIUS)) - ) +# ------------- +# List spacesys +# ------------- -@pytest.mark.parametrize( - "poly, poly_payload", - [ - (polygon1, "Polygon 57.376 24.053 56.391 24.622 56.025 24.049 56.616 24.291"), - (polygon2, "Polygon 58.376 24.053 53.391 25.622 56.025 22.049 54.616 27.291"), - ], -) -def test_polygon_spatial_request(poly, poly_payload): - polygon_region = PolygonSkyRegion(vertices=poly) - request_payload = MOCServer.query_region( - region=polygon_region, intersect="overlaps", get_query_payload=True +@pytest.fixture +def _mock_list_spacesys(monkeypatch): + # This list changes upstream. To regenerate it, do: + # >>> from astroquery.mocserver import MOCServer + # >>> hips_frames = MOCServer.query_region(meta_data="hips_frame=*", + # ... fields=["hips_frame"], + # ... spacesys=None, max_rec=100) + # >>> hips_frames.remove_column("ID") + # >>> hips_frames.write("hips_frames.vot", format="votable", overwrite=True) + with open(Path(__file__).parent / "data" / "hips_frames.vot", "rb") as f: + table = parse_single_table(f).to_table() + monkeypatch.setattr( + mocserver.MOCServerClass, "query_region", lambda self, **kwargs: table ) - assert request_payload["stc"] == poly_payload + +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +@pytest.mark.usefixtures("_mock_list_spacesys") +def test_list_spacesys(): + list_spacesys = MOCServer.list_spacesys() + assert "C" in list_spacesys and "equatorial" in list_spacesys +# --------------------- +# Special case keywords +# --------------------- + + +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +@pytest.mark.skipif(not HAS_REGIONS, reason="regions is required") @pytest.mark.parametrize("intersect", ["encloses", "overlaps", "covers"]) def test_intersect_param(intersect): center = coordinates.SkyCoord(ra=10.8, dec=32.2, unit="deg") radius = coordinates.Angle(1.5, unit="deg") - cone_region = CircleSkyRegion(center, radius) request_payload = MOCServer.query_region( region=cone_region, intersect=intersect, get_query_payload=True @@ -157,3 +175,92 @@ def test_intersect_param(intersect): assert request_payload["intersect"] == "enclosed" else: assert request_payload["intersect"] == intersect + + +def test_fields(): + # check that it works for a single field + payload = MOCServer.query_region(meta_data="", fields="ID", get_query_payload=True) + assert payload["fields"] == "ID" + # as well as more fields + payload = MOCServer.query_region( + meta_data="", fields=["ID", "hips_properties"], get_query_payload=True + ) + # cannot test the order, due to the use of set + assert "hips_properties" in payload["fields"] and "ID" in payload["fields"] + # ID has to be in fields + payload = MOCServer.query_region( + meta_data="", fields="hips_body", get_query_payload=True + ) + assert "ID" in payload["fields"] + + +def test_caseinsensitive(): + # casesensitive was hardcoded to true until astroquery 0.4.8. It is now an option + payload = MOCServer.query_region(meta_data="", fields="ID", get_query_payload=True) + assert payload["casesensitive"] == "false" + payload = MOCServer.query_region( + meta_data="", fields="ID", get_query_payload=True, casesensitive=True + ) + assert payload["casesensitive"] == "true" + + +def test_maxrec(): + payload = MOCServer.query_region(meta_data="", max_rec=100, get_query_payload=True) + assert payload["MAXREC"] == "100" + + +def test_return_moc(): + # legacy compatibility, return_moc=True means a space-MOC + payload = MOCServer.query_region( + meta_data="", return_moc=True, max_norder=5, get_query_payload=True + ) + assert payload["get"] == "moc" + assert payload["fmt"] == "ascii" + assert payload["order"] == 5 + # no max_norder means maximum order available + payload = MOCServer.query_region( + meta_data="", return_moc=True, get_query_payload=True + ) + assert payload["order"] == "max" + + +# ---------------- +# Helper functions +# ---------------- + + +@pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") +def test_parse_result(): + class MockResult: + def __init__(self, text): + self.text = text + + def json(self): + return self.text + + # all MOC types + assert isinstance(_parse_result(MockResult("0/0-11"), return_moc="moc"), MOC) + assert isinstance(_parse_result(MockResult("0/0-1"), return_moc="tmoc"), TimeMOC) + assert isinstance(_parse_result(MockResult("t3/ s5/"), return_moc="stmoc"), STMOC) + # fmoc not yet accepted + with pytest.raises(ValueError, match="'return_moc' can only take the values*"): + _parse_result(MockResult("test"), return_moc="fmoc") + # non-MOC response + assert isinstance( + _parse_result(MockResult([{"a": 0, "b": 1}]), return_moc=None), Table + ) + + +def test_cast_to_float(): + assert _cast_to_float("3") == 3 + assert _cast_to_float("test") == "test" + +# ------------ +# Deprecations +# ------------ + + +def test_find_datasets(): + # find datasets is useless as it does the same than query region + old = MOCServer.find_datasets(meta_data="ID=*Euclid*", get_query_payload=True) + assert old == MOCServer.query_region(meta_data="ID=*Euclid*", get_query_payload=True) diff --git a/astroquery/mocserver/tests/test_mocserver_remote.py b/astroquery/mocserver/tests/test_mocserver_remote.py index 82996a39ce..0bc7473115 100644 --- a/astroquery/mocserver/tests/test_mocserver_remote.py +++ b/astroquery/mocserver/tests/test_mocserver_remote.py @@ -1,49 +1,34 @@ - # Licensed under a 3-clause BSD style license - see LICENSE.rst import pytest -from astropy import coordinates from astropy.table import Table +from astropy.time import Time try: - from mocpy import MOC + from mocpy import MOC, STMOC, TimeMOC HAS_MOCPY = True except ImportError: HAS_MOCPY = False -try: - from regions import CircleSkyRegion - - HAS_REGIONS = True -except ImportError: - HAS_REGIONS = False - from ..core import MOCServer @pytest.mark.remote_data @pytest.mark.skipif(not HAS_MOCPY, reason="mocpy is required") class TestMOCServerRemote: - """ - Tests requiring regions - """ - # test of MAXREC payload - @pytest.mark.skipif(not HAS_REGIONS, reason="regions is required") @pytest.mark.parametrize("max_rec", [3, 10]) def test_max_rec_param(self, max_rec): - center = coordinates.SkyCoord(ra=10.8, dec=32.2, unit="deg") - radius = coordinates.Angle(1.5, unit="deg") - cone_region = CircleSkyRegion(center, radius) result = MOCServer.query_region( - region=cone_region, max_rec=max_rec, get_query_payload=False + region=MOC.from_str("0/0-11"), + max_rec=max_rec, + get_query_payload=False, + fields=["ID"], ) - assert max_rec == len(result) # test of field_l when retrieving dataset records - @pytest.mark.skipif(not HAS_REGIONS, reason="regions is required") @pytest.mark.parametrize( "field_l", [ @@ -52,40 +37,65 @@ def test_max_rec_param(self, max_rec): ], ) def test_field_l_param(self, field_l): - center = coordinates.SkyCoord(ra=10.8, dec=32.2, unit="deg") - radius = coordinates.Angle(1.5, unit="deg") - - cone_region = CircleSkyRegion(center, radius) - table = MOCServer.query_region( - region=cone_region, fields=field_l, get_query_payload=False + region=MOC.from_str("20/0"), fields=field_l, get_query_payload=False ) assert isinstance(table, Table) assert set(table.colnames).issubset(set(field_l)) - """ - Tests requiring mocpy - """ - # test of moc_order payload - @pytest.mark.parametrize("moc_order", [5, 10]) + @pytest.mark.parametrize("moc_order", [1, 3]) def test_moc_order_param(self, moc_order): moc_region = MOC.from_str("10/0-9") result = MOCServer.query_region( region=moc_region, return_moc=True, max_norder=moc_order, + intersect="enclosed", ) assert isinstance(result, MOC) assert result.max_order == moc_order - @pytest.mark.parametrize( - "meta_data_expr", - ["ID=*HST*", "moc_sky_fraction>0.5", "(ID=*DSS*)&&(moc_sky_fraction>0.1)"], - ) - def test_find_data_sets(self, meta_data_expr): - result = MOCServer.find_datasets( - meta_data=meta_data_expr, + def test_stmoc_as_outputs(self): + # chose a dataset with a MOC with few cells + stmoc = MOCServer.query_region( + meta_data="ID=CDS/J/AJ/157/109/table1", return_moc="stmoc" + ) + assert isinstance(stmoc, STMOC) + + def test_temporal_mocs_as_inputs(self): + tmoc = TimeMOC.from_str("11/1") + result = MOCServer.query_region( + region=tmoc, + fields=["t_min"], + max_rec=100, + meta_data="dataproduct_type='image'&&t_min=*", + ) + min_time_result = Time(result["t_min"].value, format="mjd") + # the resulting datasets should only have starting times after the + # beginning of the T-MOC + assert all(tmoc.min_time < min_time_result) + + def test_no_region(self): + result = MOCServer.query_region( + meta_data="moc_sky_fraction>0.5&&moc_sky_fraction=*", fields=["ID", "moc_sky_fraction"], + max_rec=100, ) - assert isinstance(result, Table) + assert all(result["moc_sky_fraction"] > 0.5) + + def test_query_hips(self): + result = MOCServer.query_hips(spacesys="venus", fields="hips_frame") + assert all(result["hips_frame"] == "venus") + + def test_list_fields(self): + # with keyword + moc_fields = MOCServer.list_fields("moc") + assert all("moc" in field for field in moc_fields["field_name"]) + type_moc = moc_fields[moc_fields["field_name"] == "moc_type"] + # this was the occurrence number in 2024, can only be higher in the future + assert type_moc["occurrence"][0] >= 34000 + # without keyword + all_fields = MOCServer.list_fields() + assert len(all_fields) > 100 + assert "ID" in list(all_fields["field_name"]) diff --git a/docs/mocserver/MOC_GALEXGR6_AIS_FUV.png b/docs/mocserver/MOC_GALEXGR6_AIS_FUV.png deleted file mode 100644 index 98212592f0..0000000000 Binary files a/docs/mocserver/MOC_GALEXGR6_AIS_FUV.png and /dev/null differ diff --git a/docs/mocserver/mocserver.rst b/docs/mocserver/mocserver.rst index a728ff8802..2cae9e4dbc 100644 --- a/docs/mocserver/mocserver.rst +++ b/docs/mocserver/mocserver.rst @@ -1,5 +1,3 @@ -.. doctest-skip-all - .. _astroquery.mocserver: **************************************** @@ -11,433 +9,374 @@ Getting started This module provides a python interface for querying the `CDS MOCServer`_. -MOC is an `IVOA standard`_ enabling description of arbitrary sky regions. Based on the HEALPix sky tessellation, it maps -regions on the sky into hierarchically grouped predefined cells. It corresponds to a set of HEALPix cells at different -orders. +What's a MOC? +------------- -For those wanting to know more about MOCs, please refer to this `IVOA paper -`_ and the `MOCPy's documentation -`_ developed by the CDS. +MOC means Multi-Order Coverage. It's an `IVOA standard`_ that allows to describe +Space-Time coverages of arbitrary sky regions --with or without +an associated time of observation. -CDS has set up a server known as the `MOCServer `_ storing data-set names -each associated with a MOC spatial coverage and some meta-datas giving a more detailed explanation of the data-set. +The space component maps the sky with the HEALPix sky +tessellation to represent regions on the sky by hierarchically grouped HEALPix cells. +It other words, a Spatial MOC is a set of HEALPix cells at different orders. -The MOCServer aims at returning the data-sets having at least one source lying in a specific sky region defined by the -user. Internally the MOCServer performs the intersection between the given sky region and the MOCs associated with each -data-sets. Because the MOC associated to a data-set describes its sky coverage, if the above intersection is not null -then the MOCServer knows that some sources of this data-set are in the user defined sky region. +For those wanting to know more about MOCs, please refer to `the MOC 2.0 specification +document `_. -To be aware of what the MOCServer returns, please refers to this `link -`_. -We have queried the MOCServer with a cone region of center ra, dec = (10.8, 32.2) deg and radius = 1.5 deg. In return, -the MOCServer gives a list of data-sets each tagged with an unique ID along with some other meta-datas too e.g. -``obs_title``, ``obs_description``, ``moc_access_url`` (url for accessing the MOC associated with the data-set. Usually -a FITS file storing a list of HEALPix cells). +MOCPy is a Python library allowing to manipulate these Space-Time Coverage objects. +You're welcome to have a look at `MOCPy's documentation `_. -It is also possible to ask the MOCServer for retrieving data-sets based on their meta-data values. `Here -`_ -we have queried the MOCServer for only the image data-sets being in the cone defined above (``dataproduct_type`` -meta-data equals to ``"image"``). +What's the MOC Server? +---------------------- -This package implements two methods: +The MOC Server is a service of astronomical resources organized by spatial and/or +temporal coverages following the Space and Time MOC specification. +In the MOC Server, there a few tens of thousands of astronomical collections. +They each have and identifier ``ID`` and a set of properties that describe their content. +This is a practical way of finding datasets with criteria on time and space. -* :meth:`~astroquery.mocserver.MOCServerClass.query_region` retrieving data-sets (their associated MOCs and meta-datas) having sources in a given region. -* :meth:`~astroquery.mocserver.MOCServerClass.find_datasets` retrieving data-sets (their associated MOCs and meta-datas) based on the - values of their meta-datas. +The meta-data properties are freely assigned by each publisher. You can get the list of +properties with their frequency of usage and examples example with +`astroquery.mocserver.MOCServerClass.list_fields`. +This method also accepts a string to limit the number of responses. Let's try with ``MOC``: -Requirements ----------------------------------------------------- -The following packages are required for the use of this module: +.. + We ignore output here, as occurrence is changing often +.. doctest-remote-data:: + + >>> from astroquery.mocserver import MOCServer + >>> MOCServer.list_fields("MOC") # doctest: +IGNORE_OUTPUT + + field_name occurrence example + str27 int64 str70 + ---------------- ---------- ---------------------------------------------------------------------- + moc_type 34226 smoc + moc_access_url 33084 https://alasky.unistra.fr/footprints/tables/vizier/J_AJ_165_248_tab... + moc_sky_fraction 30175 4.271E-6 + moc_order 30161 11 + moc_time_range 5319 5491 + moc_time_order 5319 35 + moc_release_date 4 2015-02-25T11:51Z + +Here, we learn that there are very few MOC-related field names. The most frequent is +``moc_type`` that will tell if the MOC is a spatial moc (``smoc``), a temporal moc +(``tmoc``)... -* `astropy-healpix`_ -* `mocpy`_ -* `regions`_ +Querying with a region +====================== -Examples -======== +The MOCServer is optimized to return the datasets having at least one source lying in a +specific sky region (or time interval). +The regions can be provided either as astropy-regions from the ``region`` python library, +or as an accepted MOC type (`mocpy.TimeMOC`, `mocpy.MOC`, `~mocpy.STMOC`). +The frequency MOCs are not yet available. -Performing a CDS MOC query on a cone region -------------------------------------------- +Performing a query on a cone region +----------------------------------- -The first thing to do is to import the `regions`_ package and the ``mocserver`` module. +Let's get the datasets for which all the data is comprised in a cone (this is +what the ``enclosed`` option means for intersect). -.. code-block:: python +.. doctest-remote-data:: >>> from astropy import coordinates >>> from regions import CircleSkyRegion >>> from astroquery.mocserver import MOCServer + >>> center = coordinates.SkyCoord(10.8, 32.2, unit='deg') + >>> radius = coordinates.Angle(0.5, unit='deg') + >>> cone = CircleSkyRegion(center, radius) + >>> MOCServer.query_region(region=cone, intersect="enclosed", spacesys="C") # doctest: +IGNORE_OUTPUT +
+ ID ... + str49 ... + ------------------------------ ... + CDS/C/GALFAHI/Narrow ... + CDS/C/GALFAHI/Narrow/DR2 ... + CDS/C/GALFAHI/Wide/DR2 ... + CDS/C/HI4PI/HI ... + CDS/I/220/out ... + CDS/I/243/out ... + CDS/I/252/out ... + CDS/I/254/out ... + CDS/I/255/out ... + ... ... + ov-gso/P/WHAM ... + simg.de/P/NSNS/DR0_1/halpha ... + simg.de/P/NSNS/DR0_1/halpha8 ... + simg.de/P/NSNS/DR0_1/hbr8 ... + simg.de/P/NSNS/DR0_1/sn-halpha ... + simg.de/P/NSNS/DR0_1/sn-vc ... + simg.de/P/NSNS/DR0_1/tc8 ... + simg.de/P/NSNS/DR0_1/vc ... + wfau.roe.ac.uk/P/UHSDR1/J ... + wfau.roe.ac.uk/UHSDR1/J ... + +You can also use this method with `regions.PolygonSkyRegion`, `mocpy.MOC`, `mocpy.TimeMOC`, +and `mocpy.STMOC`. + +Querying by meta-data +===================== + +Retrieving datasets based on their meta-data values +---------------------------------------------------- -``mocserver`` implements the method :meth:`~astroquery.mocserver.MOCServerClass.query_region` and this is what we will use. -First, we need to define a cone region. For that purpose we will instantiate a `regions.CircleSkyRegion` object: +The ``meta_data`` parameter of :meth:`~astroquery.mocserver.MOCServerClass.query_region` +allows to write an algebraic expression on the metadata. +Let's add a criteria to get only images from the previous query: -.. code-block:: python +.. doctest-remote-data:: + >>> from astropy import coordinates + >>> from regions import CircleSkyRegion + >>> from astroquery.mocserver import MOCServer >>> center = coordinates.SkyCoord(10.8, 32.2, unit='deg') - >>> radius = coordinates.Angle(1.5, unit='deg') - + >>> radius = coordinates.Angle(0.5, unit='deg') >>> cone = CircleSkyRegion(center, radius) + >>> MOCServer.query_region(region=cone, intersect="enclosed", + ... fields=['ID', 'dataproduct_type', 'moc_sky_fraction'], + ... meta_data="dataproduct_type=image") # doctest: +IGNORE_OUTPUT +
+ ID dataproduct_type moc_sky_fraction + str49 str5 float64 + ------------------------------ ---------------- ---------------- + CDS/P/2MASS/H image 1.0 + CDS/P/2MASS/J image 1.0 + CDS/P/2MASS/K image 1.0 + CDS/P/2MASS/color image 1.0 + CDS/P/AKARI/FIS/Color image 1.0 + CDS/P/AKARI/FIS/N160 image 1.0 + CDS/P/AKARI/FIS/N60 image 1.0 + CDS/P/AKARI/FIS/WideL image 1.0 + CDS/P/AKARI/FIS/WideS image 1.0 + ... ... ... + ov-gso/P/RASS/SoftBand image 1.0 + ov-gso/P/WHAM image 1.0 + simg.de/P/NSNS/DR0_1/halpha image 0.6464 + simg.de/P/NSNS/DR0_1/halpha8 image 0.6464 + simg.de/P/NSNS/DR0_1/hbr8 image 0.651 + simg.de/P/NSNS/DR0_1/sn-halpha image 0.6466 + simg.de/P/NSNS/DR0_1/sn-vc image 0.6466 + simg.de/P/NSNS/DR0_1/tc8 image 0.651 + simg.de/P/NSNS/DR0_1/vc image 0.6464 + wfau.roe.ac.uk/P/UHSDR1/J image 0.3083 + + +Looking at the ``dataproduct_type`` column, all the datasets are indeed images. + +`This page `_ on the web interface of the +MOCServer gives examples of some filtering expressions. + +Alternatively, you can search on the whole sky by ommitting the region parameter. +The next example retrieves all the ``moc_access_url`` of the Hubble surveys: + +.. doctest-remote-data:: + + >>> MOCServer.query_region(meta_data="ID=*HST*", + ... fields=['ID', 'moc_access_url'], + ... casesensitive=False) # doctest: +IGNORE_OUTPUT +
+ ID moc_access_url + str26 str51 + -------------------------- --------------------------------------------------- + CDS/P/HST-programs/3D-DASH -- + CDS/P/HST/B -- + CDS/P/HST/CO -- + CDS/P/HST/EPO -- + CDS/P/HST/GOODS/b http://alasky.unistra.fr/GOODS/GOODSb/Moc.fits + CDS/P/HST/GOODS/color http://alasky.unistra.fr/GOODS/GOODS-color/Moc.fits + CDS/P/HST/GOODS/i http://alasky.unistra.fr/GOODS/GOODSi/Moc.fits + CDS/P/HST/GOODS/v http://alasky.unistra.fr/GOODS/GOODSv/Moc.fits + CDS/P/HST/GOODS/z http://alasky.unistra.fr/GOODS/GOODSz/Moc.fits + ... ... + CDS/P/HST/Y -- + CDS/P/HST/other -- + CDS/P/HST/wideUV -- + CDS/P/HST/wideV -- + ESAVO/P/HST/ACS-blue -- + ESAVO/P/HST/FOC -- + ESAVO/P/HST/NICMOS -- + ESAVO/P/HST/WFC3 -- + ESAVO/P/HST/WFPC -- + ESAVO/P/HST/WFPC2 -- + +Query for HiPS surveys +====================== + +The MOCServer contains an extensive list of HiPS, for images and catalogs. These +progressive surveys can be displayed in applications such as Aladin or ESASky. +The `astroquery.mocserver.MOCServerClass.query_hips` method allows to find these HiPS. +It accepts the same parameters (``region`` and ``meta_data`` for example as the other) +methods. The only difference is that the output will only contain HiPS data. + +.. doctest-remote-data:: + + >>> from astroquery.mocserver import MOCServer + >>> MOCServer.query_hips(spacesys="mars") # doctest: +IGNORE_OUTPUT +
+ ID ... + str35 ... + ----------------------------------- ... + CDS/P/Mars/Express286545 ... + CDS/P/Mars/MGS-MOLA-DEM ... + CDS/P/Mars/MGS-TES-Dust ... + CDS/P/Mars/MOLA-color ... + CDS/P/Mars/MRO-CTX ... + CDS/P/Mars/TES-Albedo ... + CDS/P/Mars/TES-Thermal-Inertia ... + CDS/P/Mars/THEMIS-Day-100m-v12 ... + CDS/P/Mars/THEMIS-IR-Night-100m-v14 ... + ... ... + idoc/P/omega/emissivite_5-03mic ... + idoc/P/omega/emissivite_5-05mic ... + idoc/P/omega/emissivite_5-07mic ... + idoc/P/omega/emissivite_5-09mic ... + idoc/P/omega/ferric_bd530 ... + idoc/P/omega/ferric_nnphs ... + idoc/P/omega/olivine_osp1 ... + idoc/P/omega/olivine_osp2 ... + idoc/P/omega/olivine_osp3 ... + idoc/P/omega/pyroxene_bd2000 ... doi:10.1029/2012JE004117 ... omega pyroxene_bd2000 + +Here, we see that there are currently 25 HiPS surveys for the planet Mars available in +the MOCServer. + +Personalization of the queries +============================== + +Changing the default fields +--------------------------- + +By default, :meth:`~astroquery.mocserver.MOCServerClass.query_region` returns an +`astropy.table.Table` with information about the matching datasets. The default fields +are ``ID``, ``obs_title``, ``obs_description``, ``nb_rows``, ``obs_regime``, +``bib_reference``, and ``dataproduct_type``. +To change this default behavior, use the ``fields`` parameter. +Let's say we would like only the ``ID``, and the ``moc_sky_fraction`` for this query: + +.. doctest-remote-data:: -And basically call the :meth:`~astroquery.mocserver.MOCServerClass.query_region` method with the cone and that's all. - -.. code-block:: python - - >>> MOCServer.query_region(region=cone) -
- hips_service_url_8 hips_status hips_status_7 ... hipsgen_date_5 hips_master_url moc_sky_fraction - object object object ... object object float64 - ------------------ -------------------------- ------------- ... ----------------- -------------------------------------------------------------------------------- ---------------- - -- -- -- ... -- -- 0.0588 - -- -- -- ... -- -- 2.066e-06 - -- -- -- ... -- -- 0.002134 - -- -- -- ... -- -- 0.003107 - -- -- -- ... -- -- 0.0001764 - -- -- -- ... -- -- 0.008365 - -- -- -- ... -- -- 0.0009891 - -- -- -- ... -- -- 0.0004252 - -- -- -- ... -- -- 0.0006163 - -- -- -- ... -- -- 0.0008544 - -- -- -- ... -- -- 0.0009243 - -- -- -- ... -- -- 0.00016 - -- -- -- ... -- -- 0.000729 - -- -- -- ... -- -- 2.998e-05 - -- -- -- ... -- -- 0.01136 - -- -- -- ... -- -- 0.0006112 - -- -- -- ... -- -- 6.632e-05 - -- -- -- ... -- -- 0.0001141 - -- -- -- ... -- -- 0.0008666 - -- -- -- ... -- -- 0.001025 - -- -- -- ... -- -- 0.008088 - -- -- -- ... -- -- 0.000282 - -- -- -- ... -- -- 0.002413 - -- -- -- ... -- -- 0.0001468 - -- public master clonableOnce -- ... -- -- 0.3164 - -- public master clonableOnce -- ... -- -- 1.0 - -- -- -- ... -- -- 4.444e-05 - -- -- -- ... -- -- 4.641e-05 - -- -- -- ... -- -- 0.00044 - ... ... ... ... ... ... ... - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- http://cade.irap.omp.eu/documents/Ancillary/4Aladin/DRAO-VillaElisa_21cm_POLQ 1.0 - -- public master unclonable -- ... -- http://cade.irap.omp.eu/documents/Ancillary/4Aladin/DRAO-VillaElisa_21cm_POLU 1.0 - -- public master unclonable -- ... -- http://cade.irap.omp.eu/documents/Ancillary/4Aladin/DRAO_22MHz 0.7283 - -- public master unclonable -- ... 2017-02-09T13:48Z -- 0.5723 - -- public master unclonable -- ... -- -- 0.5468 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- http://cade.irap.omp.eu/documents/Ancillary/4Aladin/GAURIBIDANUR/ 0.8623 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 0.9635 - -- public master unclonable -- ... -- -- 0.4284 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- -- 1.0 - -- public master unclonable -- ... -- http://cade.irap.omp.eu/documents/Ancillary/4Aladin/STOCKERT+VILLAELISA_1420MHz/ 1.0 - -- public master unclonable -- ... -- -- 0.181 - -- public master unclonable -- ... -- -- 0.1918 - -- public master unclonable -- ... 2017-05-15T12:44Z -- 1.0 - -- -- -- ... -- -- 0.1553 - -- -- -- ... -- -- 0.2373 - -- public master clonableOnce -- ... -- -- 0.08287 - -- public master clonableOnce -- ... -- -- 0.02227 - -- public master clonableOnce -- ... -- -- 0.02227 - -- public master clonableOnce -- ... -- -- 0.02227 - -You can also query the MOCServer on a `regions.PolygonSkyRegion` or even an `mocpy.MOC` following the same pattern i.e. just -by replacing ``cone`` with a polygon or a MOC object. - - -By default, :meth:`~astroquery.mocserver.MOCServerClass.query_region` returns an `astropy.table.Table` object storing the data-sets -as rows and their meta-datas as columns. Data-sets might have no information for a specific meta-data. If so, the value -associated with this meta-data for this data-set is set to "-". The above astropy table looks like : - - -Retrieve only a subset of meta-datas ------------------------------------- - -This table refers to a lot of meta-datas whereas we could only use a few of them. In fact, it is possible to ask the -MOCServer to give us a reduced set of meta-datas for the resulting data-sets. The table returned by the MOCServer -will be lighter and thus faster to retrieve. - -The parameter ``fields`` of :meth:`~astroquery.mocserver.MOCServerClass.query_region` allows us to provide the list of meta-datas we -want to get. Let's say we would like only the ``ID``, the ``moc_sky_fraction`` and the ``moc_access_url`` of the -resulting data-sets: - -.. code-block:: python - - >>> MOCServer.query_region(region=cone, fields=['ID', 'moc_sky_fraction', 'moc_access_url']) -
- moc_access_url ID moc_sky_fraction - object str48 float64 - ------------------------------------------------------------------------------------ ------------------------------------ ---------------- - http://alasky.unistra.fr/footprints/tables/vizier/B_assocdata_obscore/MOC?nside=2048 CDS/B/assocdata/obscore 0.0588 - http://alasky.unistra.fr/footprints/tables/vizier/B_cb_lmxbdata/MOC?nside=2048 CDS/B/cb/lmxbdata 2.066e-06 - http://alasky.unistra.fr/footprints/tables/vizier/B_cfht_cfht/MOC?nside=2048 CDS/B/cfht/cfht 0.002134 - http://alasky.unistra.fr/footprints/tables/vizier/B_cfht_obscore/MOC?nside=2048 CDS/B/cfht/obscore 0.003107 - http://alasky.unistra.fr/footprints/tables/vizier/B_chandra_chandra/MOC?nside=2048 CDS/B/chandra/chandra 0.0001764 - http://alasky.unistra.fr/footprints/tables/vizier/B_eso_eso_arc/MOC?nside=2048 CDS/B/eso/eso_arc 0.008365 - http://alasky.unistra.fr/footprints/tables/vizier/B_gcvs_gcvs_cat/MOC?nside=2048 CDS/B/gcvs/gcvs_cat 0.0009891 - http://alasky.unistra.fr/footprints/tables/vizier/B_gcvs_nsv_cat/MOC?nside=2048 CDS/B/gcvs/nsv_cat 0.0004252 - http://alasky.unistra.fr/footprints/tables/vizier/B_gemini_obscore/MOC?nside=2048 CDS/B/gemini/obscore 0.0006163 - http://alasky.unistra.fr/footprints/tables/vizier/B_hst_hstlog/MOC?nside=2048 CDS/B/hst/hstlog 0.0008544 - http://alasky.unistra.fr/footprints/tables/vizier/B_hst_obscore/MOC?nside=2048 CDS/B/hst/obscore 0.0009243 - http://alasky.unistra.fr/footprints/tables/vizier/B_hst_wfpc2/MOC?nside=2048 CDS/B/hst/wfpc2 0.00016 - http://alasky.unistra.fr/footprints/tables/vizier/B_jcmt_obscore/MOC?nside=2048 CDS/B/jcmt/obscore 0.000729 - http://alasky.unistra.fr/footprints/tables/vizier/B_merlin_merlin/MOC?nside=2048 CDS/B/merlin/merlin 2.998e-05 - http://alasky.unistra.fr/footprints/tables/vizier/B_mk_mktypes/MOC?nside=2048 CDS/B/mk/mktypes 0.01136 - http://alasky.unistra.fr/footprints/tables/vizier/B_pastel_pastel/MOC?nside=2048 CDS/B/pastel/pastel 0.0006112 - http://alasky.unistra.fr/footprints/tables/vizier/B_sb9_main/MOC?nside=2048 CDS/B/sb9/main 6.632e-05 - http://alasky.unistra.fr/footprints/tables/vizier/B_sn_sncat/MOC?nside=2048 CDS/B/sn/sncat 0.0001141 - http://alasky.unistra.fr/footprints/tables/vizier/B_subaru_suprimc/MOC?nside=2048 CDS/B/subaru/suprimc 0.0008666 - http://alasky.unistra.fr/footprints/tables/vizier/B_swift_swiftlog/MOC?nside=2048 CDS/B/swift/swiftlog 0.001025 - http://alasky.unistra.fr/footprints/tables/vizier/B_vsx_vsx/MOC?nside=2048 CDS/B/vsx/vsx 0.008088 - http://alasky.unistra.fr/footprints/tables/vizier/B_wd_catalog/MOC?nside=2048 CDS/B/wd/catalog 0.000282 - http://alasky.unistra.fr/footprints/tables/vizier/B_wds_wds/MOC?nside=2048 CDS/B/wds/wds 0.002413 - http://alasky.unistra.fr/footprints/tables/vizier/B_xmm_xmmlog/MOC?nside=2048 CDS/B/xmm/xmmlog 0.0001468 - -- CDS/C/GALFAHI/Narrow 0.3164 - -- CDS/C/HI4PI/HI 1.0 - http://alasky.unistra.fr/footprints/tables/vizier/I_100A_w10/MOC?nside=2048 CDS/I/100A/w10 4.444e-05 - http://alasky.unistra.fr/footprints/tables/vizier/I_100A_w25/MOC?nside=2048 CDS/I/100A/w25 4.641e-05 - http://alasky.unistra.fr/footprints/tables/vizier/I_100A_w50/MOC?nside=2048 CDS/I/100A/w50 0.00044 - ... ... ... - -- ov-gso/P/DIRBE/ZSMA9 1.0 - -- ov-gso/P/DRAO-VillaElisa/21cm/POLQ 1.0 - -- ov-gso/P/DRAO-VillaElisa/21cm/POLU 1.0 - -- ov-gso/P/DRAO/22MHz 0.7283 - -- ov-gso/P/DWINGELOO/820MHz 0.5723 - -- ov-gso/P/EBHIS 0.5468 - -- ov-gso/P/GASS+EBHIS 1.0 - -- ov-gso/P/GAURIBIDANUR 0.8623 - -- ov-gso/P/IRIS/1 1.0 - -- ov-gso/P/IRIS/2 1.0 - -- ov-gso/P/IRIS/3 1.0 - -- ov-gso/P/IRIS/4 1.0 - -- ov-gso/P/LAB 1.0 - -- ov-gso/P/MAIPU-MU 0.9635 - -- ov-gso/P/MITEoR 0.4284 - -- ov-gso/P/RASS 1.0 - -- ov-gso/P/RASS/EXP 1.0 - -- ov-gso/P/RASS/HardBand 1.0 - -- ov-gso/P/RASS/SoftBand 1.0 - -- ov-gso/P/STOCKERT+VILLAELISA/1420MHz 1.0 - -- ov-gso/P/VTSS/CONT 0.181 - -- ov-gso/P/VTSS/Ha 0.1918 - -- ov-gso/P/WHAM 1.0 - -- svo.cab/cat/catlib 0.1553 - -- svo.cab/cat/miles 0.2373 - -- xcatdb/P/XMM/PN/color 0.08287 - -- xcatdb/P/XMM/PN/eb2 0.02227 - -- xcatdb/P/XMM/PN/eb3 0.02227 - -- xcatdb/P/XMM/PN/eb4 0.02227 - -This astropy table now have only 3 columns and can be manipulated much faster. - -Retrieving data-sets based on their meta-data values ----------------------------------------------------- - -As expressed in the last paragraph of the Getting Started section, we can ask the MOCServer to do some filtering tasks for us -at the server side. The ``meta_data`` parameter of :meth:`~astroquery.mocserver.MOCServerClass.query_region` allows the user to -write an algebraic expression on the meta-datas. Let's query the MOCServer for retrieving what we have done using the -web interface in the Getting Started section i.e. retrieving only the image data-sets that lie in the previously defined cone. - -.. code-block:: python - - >>> MOCServer.query_region(region=cone, - ... fields=['ID', 'dataproduct_type', 'moc_sky_fraction', 'moc_access_url'], - ... meta_data="dataproduct_type=image") -
- moc_access_url ID dataproduct_type moc_sky_fraction - object str48 str5 float64 - ------------------------------------------------------------------------ --------------------------------------- ---------------- ---------------- - http://alasky.u-strasbg.fr/2MASS/H/Moc.fits CDS/P/2MASS/H image 1.0 - http://alasky.u-strasbg.fr/2MASS/J/Moc.fits CDS/P/2MASS/J image 1.0 - http://alasky.u-strasbg.fr/2MASS/K/Moc.fits CDS/P/2MASS/K image 1.0 - http://alasky.u-strasbg.fr/2MASS/Color/Moc.fits CDS/P/2MASS/color image 1.0 - http://alasky.u-strasbg.fr/AKARI-FIS/ColorLSN60/Moc.fits CDS/P/AKARI/FIS/Color image 1.0 - http://alasky.u-strasbg.fr/AKARI-FIS/N160/Moc.fits CDS/P/AKARI/FIS/N160 image 0.9988 - http://alasky.u-strasbg.fr/AKARI-FIS/N60/Moc.fits CDS/P/AKARI/FIS/N60 image 0.9976 - http://alasky.u-strasbg.fr/AKARI-FIS/WideL/Moc.fits CDS/P/AKARI/FIS/WideL image 0.9989 - http://alasky.u-strasbg.fr/AKARI-FIS/WideS/Moc.fits CDS/P/AKARI/FIS/WideS image 0.9976 - -- CDS/P/Ariel/Voyager image 1.0 - http://alasky.u-strasbg.fr/CO/Moc.fits CDS/P/CO image 1.0 - -- CDS/P/Callisto/Voyager-Galileo-simp-1km image 1.0 - -- CDS/P/Charon/NewHorizon-PIA19866 image 1.0 - -- CDS/P/DM/flux-Bp/I/345/gaia2 image 1.0 - -- CDS/P/DM/flux-G/I/345/gaia2 image 1.0 - -- CDS/P/DM/flux-Rp/I/345/gaia2 image 1.0 - -- CDS/P/DM/flux-color-Rp-G-Bp/I/345/gaia2 image 1.0 - -- CDS/P/DSS2/NIR image 0.9943 - http://alasky.u-strasbg.fr/DSS/DSS2-blue-XJ-S/Moc.fits CDS/P/DSS2/blue image 0.9956 - http://alasky.u-strasbg.fr/DSS/DSSColor/Moc.fits CDS/P/DSS2/color image 1.0 - http://alasky.u-strasbg.fr/DSS/DSS2Merged/Moc.fits CDS/P/DSS2/red image 1.0 - -- CDS/P/Dione/Cassini-PIA12577 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_100-150/Moc.fits CDS/P/EGRET/Dif/100-150 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_1000-2000/Moc.fits CDS/P/EGRET/Dif/1000-2000 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_150-300/Moc.fits CDS/P/EGRET/Dif/150-300 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_2000-4000/Moc.fits CDS/P/EGRET/Dif/2000-4000 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_30-50/Moc.fits CDS/P/EGRET/Dif/30-50 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_300-500/Moc.fits CDS/P/EGRET/Dif/300-500 image 1.0 - http://alasky.u-strasbg.fr/EGRET/EGRET-dif/EGRET_dif_4000-10000/Moc.fits CDS/P/EGRET/Dif/4000-10000 image 1.0 - ... ... ... ... - -- ov-gso/P/DIRBE/ZSMA7 image 1.0 - -- ov-gso/P/DIRBE/ZSMA8 image 1.0 - -- ov-gso/P/DIRBE/ZSMA9 image 1.0 - -- ov-gso/P/DRAO-VillaElisa/21cm/POLQ image 1.0 - -- ov-gso/P/DRAO-VillaElisa/21cm/POLU image 1.0 - -- ov-gso/P/DRAO/22MHz image 0.7283 - -- ov-gso/P/DWINGELOO/820MHz image 0.5723 - -- ov-gso/P/EBHIS image 0.5468 - -- ov-gso/P/GASS+EBHIS image 1.0 - -- ov-gso/P/GAURIBIDANUR image 0.8623 - -- ov-gso/P/IRIS/1 image 1.0 - -- ov-gso/P/IRIS/2 image 1.0 - -- ov-gso/P/IRIS/3 image 1.0 - -- ov-gso/P/IRIS/4 image 1.0 - -- ov-gso/P/LAB image 1.0 - -- ov-gso/P/MAIPU-MU image 0.9635 - -- ov-gso/P/MITEoR image 0.4284 - -- ov-gso/P/RASS image 1.0 - -- ov-gso/P/RASS/EXP image 1.0 - -- ov-gso/P/RASS/HardBand image 1.0 - -- ov-gso/P/RASS/SoftBand image 1.0 - -- ov-gso/P/STOCKERT+VILLAELISA/1420MHz image 1.0 - -- ov-gso/P/VTSS/CONT image 0.181 - -- ov-gso/P/VTSS/Ha image 0.1918 - -- ov-gso/P/WHAM image 1.0 - -- xcatdb/P/XMM/PN/color image 0.08287 - -- xcatdb/P/XMM/PN/eb2 image 0.02227 - -- xcatdb/P/XMM/PN/eb3 image 0.02227 - -- xcatdb/P/XMM/PN/eb4 image 0.02227 - - -Looking at the ``dataproduct_type`` column, all the data-sets seem to be images. We could have been done that using -numpy operations on `astropy.table.Table` objects but here the MOCServer made it for us. - -`This page `_ on the web interface of the MOCServer gives examples of some filtering expressions. - -Alternatively, the method :meth:`~astroquery.mocserver.MOCServerClass.find_datasets` searches data-sets on the whole sky. If you want -to get the MOCs or meta-datas from some specific data-sets this is the method to use. The next example retrieves all the -``moc_access_url`` of the Hubble surveys: - -.. code-block:: python - - >>> MOCServer.find_datasets(meta_data="ID=*HST*", - ... fields=['ID', 'moc_access_url']) -
- moc_access_url ID - object str21 - --------------------------------------------------- --------------------- - -- CDS/P/HST/B - -- CDS/P/HST/CO - http://alasky.unistra.fr/GOODS/GOODSb/Moc.fits CDS/P/HST/GOODS/b - http://alasky.unistra.fr/GOODS/GOODS-color/Moc.fits CDS/P/HST/GOODS/color - http://alasky.unistra.fr/GOODS/GOODSi/Moc.fits CDS/P/HST/GOODS/i - http://alasky.unistra.fr/GOODS/GOODSv/Moc.fits CDS/P/HST/GOODS/v - http://alasky.unistra.fr/GOODS/GOODSz/Moc.fits CDS/P/HST/GOODS/z - -- CDS/P/HST/H - -- CDS/P/HST/H2O - -- CDS/P/HST/Halpha - -- CDS/P/HST/Hbeta - -- CDS/P/HST/I - -- CDS/P/HST/J - -- CDS/P/HST/NII - -- CDS/P/HST/OII - -- CDS/P/HST/OIII - http://alasky.u-strasbg.fr/PHAT/F110W/Moc.fits CDS/P/HST/PHAT/F110W - http://alasky.u-strasbg.fr/PHAT/F160W/Moc.fits CDS/P/HST/PHAT/F160W - http://alasky.u-strasbg.fr/PHAT/F275W/Moc.fits CDS/P/HST/PHAT/F275W - http://alasky.u-strasbg.fr/PHAT/F336W/Moc.fits CDS/P/HST/PHAT/F336W - http://alasky.u-strasbg.fr/PHAT/F475W/Moc.fits CDS/P/HST/PHAT/F475W - http://alasky.u-strasbg.fr/PHAT/F814W/Moc.fits CDS/P/HST/PHAT/F814W - -- CDS/P/HST/Palpha - -- CDS/P/HST/Palpha_c - -- CDS/P/HST/R - -- CDS/P/HST/SDSSg - -- CDS/P/HST/SDSSr - -- CDS/P/HST/SDSSz - -- CDS/P/HST/SIII - -- CDS/P/HST/U - -- CDS/P/HST/UV - -- CDS/P/HST/V - -- CDS/P/HST/Y - -- CDS/P/HST/other - -- CDS/P/HST/wideUV - -- CDS/P/HST/wideV - -- ESAVO/P/HST/ACS-blue - -- ESAVO/P/HST/FOC - -- ESAVO/P/HST/NICMOS - -- ESAVO/P/HST/WFC3 - -- ESAVO/P/HST/WFPC - -- ESAVO/P/HST/WFPC2 - -Misc ----- - -Limiting the number of returned data-sets -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + >>> from astropy import coordinates + >>> from regions import CircleSkyRegion + >>> from astroquery.mocserver import MOCServer + >>> center = coordinates.SkyCoord(10.8, 32.2, unit='deg') + >>> radius = coordinates.Angle(0.5, unit='deg') + >>> cone = CircleSkyRegion(center, radius) + >>> MOCServer.query_region(region=cone, + ... intersect="enclosed", + ... fields=['ID', 'moc_sky_fraction']) # doctest: +IGNORE_OUTPUT +
+ ID moc_sky_fraction + str49 float64 + CDS/I/220/out 0.9697 + CDS/I/243/out 1.0 + CDS/I/252/out 0.9993 + CDS/I/254/out 1.0 + CDS/I/255/out 0.9696 + ... ... + ov-gso/P/WHAM 1.0 + simg.de/P/NSNS/DR0_1/halpha 0.6464 + simg.de/P/NSNS/DR0_1/halpha8 0.6464 + simg.de/P/NSNS/DR0_1/hbr8 0.651 + simg.de/P/NSNS/DR0_1/sn-halpha 0.6466 + +We now see in a single glance that the dataset ``CDS/I/220/out`` covers almost all the +sky! + +Limiting the number of returned datasets +---------------------------------------- Another parameter called ``max_rec`` specifies an upper limit for the number of data-sets to be returned: -.. code-block:: python +.. doctest-remote-data:: - >>> MOCServer.query_region(region=cone, max_rec=3) -
- publisher_id obs_description_url moc_access_url ... TIMESTAMP obs_label moc_sky_fraction - str9 str52 str84 ... float64 str8 float64 - ------------ ---------------------------------------------------- ------------------------------------------------------------------------------------ ... --------------- --------- ---------------- - ivo://CDS http://cdsarc.u-strasbg.fr/viz-bin/Cat?B%2Fassocdata http://alasky.unistra.fr/footprints/tables/vizier/B_assocdata_obscore/MOC?nside=2048 ... 1531742659000.0 obscore 0.0588 - ivo://CDS http://cdsarc.u-strasbg.fr/viz-bin/Cat?B%2Fcb http://alasky.unistra.fr/footprints/tables/vizier/B_cb_lmxbdata/MOC?nside=2048 ... 1531742660000.0 lmxbdata 2.066e-06 - ivo://CDS http://cdsarc.u-strasbg.fr/viz-bin/Cat?B%2Fcfht http://alasky.unistra.fr/footprints/tables/vizier/B_cfht_cfht/MOC?nside=2048 ... 1531742660000.0 cfht 0.002134 + >>> from astroquery.mocserver import MOCServer + >>> from mocpy import MOC + >>> MOCServer.query_region(region=MOC.from_string("5/22-24"), max_rec=3) # doctest: +IGNORE_OUTPUT +
+ ID ... dataproduct_type + str24 ... str7 + ------------------------ ... ---------------- + CDS/J/AJ/156/102/table9 ... catalog + CDS/J/ApJS/257/54/table1 ... catalog + CDS/III/39A/catalog ... catalog -This astropy table has only 3 rows although we know more data-sets match the query. It's useful if you do not need -to retrieve all the data-sets matching a query but only a few. Again, the result will come faster from the MOCServer because -this operation is done at the server side. +This astropy has only 3 rows although we know that more datasets match the query. +The result will come faster than requesting all results. -Returning a `~mocpy.MOC` object as a result -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Returning a ``mocpy`` object as a result +---------------------------------------- -Some users might want the union of all the MOCs from the data-sets matching the query. You can get a `mocpy.MOC` object -instead of an `astropy.table.Table` by setting the parameter ``return_moc`` to True. An additional parameter ``max_norder`` -allows the user to set the resolution/precision of the returned MOC that he wants. +I you need want the union of all the MOCs of the datasets matching the query, you can +get the result as a `mocpy.MOC`, `mocpy.TimeMOC`, or `mocpy.STMOC` object instead of an +`astropy.table.Table` by setting the parameter ``return_moc`` to ``smoc``, ``tmoc``, or +``stmoc``. An additional parameter ``max_norder`` allows to set the resolution/precision +of the returned MOC. -As an example, we would like to obtain the union of the spatial coverage of all the Hubble surveys: +As an example, we would like to obtain the union of the space coverage of all the +Hubble surveys: -.. code-block:: python +.. doctest-remote-data:: >>> from mocpy import MOC - >>> # We want to retrieve all the HST surveys i.e. the HST surveys covering any region of the sky. - >>> allsky = CircleSkyRegion(coordinates.SkyCoord(0, 0, unit="deg"), coordinates.Angle(180, unit="deg")) - >>> moc = MOCServer.query_region(region=allsky, - ... # We want a mocpy object instead of an astropy table - ... return_moc=True, - ... # The order of the MOC - ... max_norder=7, - ... # Expression on the ID meta-data - ... meta_data="ID=*HST*") - >>> moc.plot(title="Union of the spatial coverage of all the Hubble surveys.") + >>> import matplotlib.pyplot as plt + >>> from astroquery.mocserver import MOCServer + >>> moc = MOCServer.query_region(return_moc="smoc", + ... max_norder=20, + ... meta_data="ID=*HST*") + +The resulting MOC looks like: -.. image:: ./HST_union.png +.. image:: HST_union -Retrieve the `~mocpy.MOC` of a specific data-set -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Retrieve the `~mocpy.STMOC` of a specific dataset +------------------------------------------------- -Finally, if you want to retrieve the MOC of a specific data-set, please consider using the `~astroquery.mocserver.MOCServerClass.find_datasets` -method with the ID of the data-set you want to retrieve the MOC along with the ``return_moc`` parameter set to True. -The last example will show you how to get the MOC (i.e. a `mocpy.MOC` object) of the ``GALEXGR6/AIS/FUV`` survey. +To retrieve the MOC of a specific dataset, we can use +`~astroquery.mocserver.MOCServerClass.query_region`. +This example will show you how to get the space-time MOC (i.e. a `mocpy.STMOC` +object) of the ``GALEXGR6/AIS/FUV`` survey. -.. code-block:: python +.. doctest-remote-data:: >>> from mocpy import MOC - >>> moc_galex= MOCServer.find_datasets(meta_data="ID=CDS/P/GALEXGR6/AIS/FUV", return_moc=True) - >>> moc_galex.plot("MOC associated to CDS/P/GALEXGR6/AIS/FUV.") + >>> from astroquery.mocserver import MOCServer + >>> moc_galex = MOCServer.query_region(meta_data="ID=CDS/P/GALEXGR6/AIS/FUV", + ... return_moc="stmoc", max_norder="s7 t26") + >>> print(f"GALEX GR6 contains data taken from {moc_galex.min_time.iso} to" + ... f" {moc_galex.max_time.iso}.") + GALEX GR6 contains data taken from 2010-03-31 18:02:05.602 to 2010-06-01 18:57:24.787. + + +The ``mocserver`` package can therefore be used in complementarity with `mocpy`_. +We can now retrieve `mocpy.MOC` objects coming from the MOCServer and manipulate them +with `mocpy`_. + +Finding data on a specific solar system body +-------------------------------------------- + +The default value for ``spacesys`` is None. It means that we're looking for data for the +sky and all other possible frames. This can take all the values listed by +`astroquery.mocserver.MOCServerClass.list_spacesys`: + +.. doctest-remote-data:: + + >>> from astroquery.mocserver import MOCServer + >>> MOCServer.list_spacesys() + ['C', 'ariel', 'callisto', 'ceres', 'charon', 'dione', 'earth', 'enceladus', 'equatorial', 'europa', 'galactic', 'ganymede', 'iapetus', 'io', 'jupiter', 'mars', 'mars-pia20284', 'mars-pia24422', 'mars-stimson', 'mercury', 'mimas', 'miranda', 'moon', 'moon-pan1', 'neptune', 'oberon', 'pluto', 'rhea', 'sun', 'tethys', 'titan', 'titania', 'triton', 'umbriel', 'venus'] + +Where the special value ``C`` means any celestial frame (mainly ``equatorial`` and +``galactic``). This can be used in any of the query methods like so: + +.. doctest-remote-data:: -.. image:: ./MOC_GALEXGR6_AIS_FUV.png + >>> from astroquery.mocserver import MOCServer + >>> MOCServer.query_hips(spacesys="ariel") # doctest: +IGNORE_OUTPUT +
+ ID obs_title obs_description dataproduct_type + str19 str13 str65 str5 + ------------------- ------------- ----------------------------------------------------------------- ---------------- + CDS/P/Ariel/Voyager Ariel Voyager Ariel Uranus satellite map mosaicked with Voyager imagery by USGS image -The ``mocserver`` package can therefore be used in complementarity with `mocpy`_. We can now retrieve `mocpy.MOC` objects -coming from the MOCServer and manipulate them in a python session with `mocpy`_. Reference/API =============