Skip to content

Commit 8a31a69

Browse files
committed
initial code to restore rectangle
1 parent 766a4fc commit 8a31a69

File tree

1 file changed

+146
-48
lines changed

1 file changed

+146
-48
lines changed

astroquery/sdss/core.py

Lines changed: 146 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ def query_crossid_async(self, coordinates, *, radius=5. * u.arcsec, timeout=TIME
6666
6767
This query returns the nearest `primary object`_.
6868
69+
Note that there is a server-side limit of 3 arcmin on `radius`.
70+
6971
.. _`primary object`: https://www.sdss.org/dr17/help/glossary/#surveyprimary
7072
7173
Parameters
@@ -129,6 +131,13 @@ def query_crossid_async(self, coordinates, *, radius=5. * u.arcsec, timeout=TIME
129131
result : `~astropy.table.Table`
130132
The result of the query as a `~astropy.table.Table` object.
131133
134+
Raises
135+
------
136+
TypeError
137+
If the `radius` keyword could not be parsed as an angle.
138+
ValueError
139+
If the `radius` exceeds 3 arcmin, or if the sizes of
140+
`coordinates` and `obj_names` do not match.
132141
"""
133142

134143
if isinstance(radius, Angle):
@@ -193,16 +202,27 @@ def query_crossid_async(self, coordinates, *, radius=5. * u.arcsec, timeout=TIME
193202
timeout=timeout, cache=cache)
194203
return response
195204

196-
def query_region_async(self, coordinates, *, radius=2. * u.arcsec, timeout=TIMEOUT,
205+
def query_region_async(self, coordinates, *, radius=None,
206+
width=None, height=None, timeout=TIMEOUT,
197207
fields=None, photoobj_fields=None, specobj_fields=None, obj_names=None,
198208
spectro=False, field_help=False, get_query_payload=False,
199209
data_release=conf.default_release, cache=True):
200-
"""
201-
Used to query a circular region (a "cone search") around given coordinates.
202-
203-
This function is equivalent to the object cross-ID (`query_crossid`),
204-
with slightly different parameters. It returns all objects within the
205-
search radius; this could potentially include duplicate observations
210+
"""Used to query a region around given coordinates. Either `radius` or
211+
`width` must be specified.
212+
213+
When called with keyword `radius`, a radial or "cone" search is
214+
performed, centered on each of the given coordinates. In this mode, internally,
215+
this function is equivalent to the object cross-ID (`query_crossid`),
216+
with slightly different parameters. Note that in this mode there is a server-side
217+
limit of 3 arcmin on `radius`.
218+
219+
When called with keyword `width`, and optionally a different `height`,
220+
a rectangular search is performed, centered on each of the given
221+
coordinates. In this mode, internally, this function is equivalent to
222+
a general SQL query (`query_sql`).
223+
224+
In both radial and rectangular modes, this function returns all objects
225+
within the search area; this could potentially include duplicate observations
206226
of the same object.
207227
208228
Parameters
@@ -221,8 +241,17 @@ def query_region_async(self, coordinates, *, radius=2. * u.arcsec, timeout=TIMEO
221241
radius : str or `~astropy.units.Quantity` object, optional
222242
The string must be parsable by `~astropy.coordinates.Angle`. The
223243
appropriate `~astropy.units.Quantity` object from
224-
`astropy.units` may also be used. Defaults to 2 arcsec.
244+
`astropy.units` may also be used.
225245
The maximum allowed value is 3 arcmin.
246+
width : str or `~astropy.units.Quantity` object, optional
247+
The string must be parsable by `~astropy.coordinates.Angle`. The
248+
appropriate `~astropy.units.Quantity` object from
249+
`astropy.units` may also be used.
250+
height : str or `~astropy.units.Quantity` object, optional
251+
The string must be parsable by `~astropy.coordinates.Angle`. The
252+
appropriate `~astropy.units.Quantity` object from
253+
`astropy.units` may also be used. If not specified, it will be
254+
set to the same value as `width`.
226255
timeout : float, optional
227256
Time limit (in seconds) for establishing successful connection with
228257
remote server. Defaults to `SDSSClass.TIMEOUT`.
@@ -256,6 +285,19 @@ def query_region_async(self, coordinates, *, radius=2. * u.arcsec, timeout=TIMEO
256285
cache : bool, optional
257286
If ``True`` use the request caching mechanism.
258287
288+
Returns
289+
-------
290+
result : `~astropy.table.Table`
291+
The result of the query as a `~astropy.table.Table` object.
292+
293+
Raises
294+
------
295+
TypeError
296+
If the `radius`, `width` or `height` keywords could not be parsed as an angle.
297+
ValueError
298+
If both `radius` and `width or set, or if the `radius` exceeds 3 arcmin,
299+
or if the sizes of `coordinates` and `obj_names` do not match.
300+
259301
Examples
260302
--------
261303
>>> from astroquery.sdss import SDSS
@@ -270,23 +312,83 @@ def query_region_async(self, coordinates, *, radius=2. * u.arcsec, timeout=TIMEO
270312
2.02344596595 14.8398237229 1237652943176138867 1739 301 3 315
271313
2.02344596303 14.8398237521 1237652943176138868 1739 301 3 315
272314
2.02344772021 14.8398201105 1237653651835781243 1904 301 3 163
273-
274-
Returns
275-
-------
276-
result : `~astropy.table.Table`
277-
The result of the query as a `~astropy.table.Table` object.
278-
279315
"""
280-
request_payload, files = self.query_crossid_async(coordinates=coordinates,
281-
radius=radius, fields=fields,
282-
photoobj_fields=photoobj_fields,
283-
specobj_fields=specobj_fields,
284-
obj_names=obj_names,
285-
spectro=spectro,
286-
region=True,
287-
field_help=field_help,
288-
get_query_payload=True,
289-
data_release=data_release)
316+
if radius is not None and width is not None:
317+
raise ValueError("One or the other of radius or width must be selected!")
318+
319+
if radius is not None:
320+
request_payload, files = self.query_crossid_async(coordinates=coordinates,
321+
radius=radius, fields=fields,
322+
photoobj_fields=photoobj_fields,
323+
specobj_fields=specobj_fields,
324+
obj_names=obj_names,
325+
spectro=spectro,
326+
region=True,
327+
field_help=field_help,
328+
get_query_payload=True,
329+
data_release=data_release)
330+
331+
if width is not None:
332+
if isinstance(width, Angle):
333+
width = width.to_value(u.arcmin)
334+
else:
335+
try:
336+
width = Angle(width).to_value(u.arcmin)
337+
except ValueError:
338+
raise TypeError("width should be either Quantity or "
339+
"convertible to float.")
340+
if height is None:
341+
height = width
342+
else:
343+
if isinstance(height, Angle):
344+
height = height.to_value(u.arcmin)
345+
else:
346+
try:
347+
height = Angle(height).to_value(u.arcmin)
348+
except ValueError:
349+
raise TypeError("height should be either Quantity or "
350+
"convertible to float.")
351+
352+
dummy_payload = self._args_to_payload(coordinates=coordinates,
353+
fields=fields,
354+
spectro=spectro, region=True,
355+
photoobj_fields=photoobj_fields,
356+
specobj_fields=specobj_fields, field_help=field_help,
357+
data_release=data_release)
358+
359+
sql_query = dummy_payload['uquery'].replace('#upload u JOIN #x x ON x.up_id = u.up_id JOIN ', '')
360+
361+
if 'SpecObjAll' in dummy_payload['uquery']:
362+
sql_query = sql_query.replace('ON p.objID = x.objID ', '').replace(' ORDER BY x.up_id', '')
363+
else:
364+
sql_query = sql_query.replace(' ON p.objID = x.objID ORDER BY x.up_id', '')
365+
366+
if (not isinstance(coordinates, list) and
367+
not isinstance(coordinates, Column) and
368+
not (isinstance(coordinates, commons.CoordClasses) and
369+
not coordinates.isscalar)):
370+
coordinates = [coordinates]
371+
rectangles = list()
372+
for n, target in enumerate(coordinates):
373+
# Query for a rectangle
374+
target = commons.parse_coordinates(target).transform_to('fk5')
375+
376+
ra = target.ra.degree
377+
dec = target.dec.degree
378+
dra = coord.Angle(width).to('degree').value / 2.0
379+
ddec = coord.Angle(height).to('degree').value / 2.0
380+
rectangles.append('((p.ra BETWEEN {0:g} AND {1:g}) AND (p.dec BETWEEN {2:g} AND {3:g}))'.format(ra - dra, ra + dra, dec - ddec, dec + ddec))
381+
rect = ' OR '.join(rectangles)
382+
if 'WHERE' in sql_query:
383+
sql_query += f' AND ({rect})'
384+
else:
385+
sql_query += f' WHERE ({rect})'
386+
387+
return self.query_sql_async(sql_query, timeout=timeout,
388+
data_release=data_release,
389+
cache=cache,
390+
field_help=field_help,
391+
get_query_payload=get_query_payload)
290392

291393
if get_query_payload or field_help:
292394
return request_payload
@@ -335,6 +437,11 @@ def query_specobj_async(self, *, plate=None, mjd=None, fiberID=None,
335437
cache : bool, optional
336438
If ``True`` use the request caching mechanism.
337439
440+
Returns
441+
-------
442+
result : `~astropy.table.Table`
443+
The result of the query as an `~astropy.table.Table` object.
444+
338445
Examples
339446
--------
340447
>>> from astroquery.sdss import SDSS
@@ -348,12 +455,6 @@ def query_specobj_async(self, *, plate=None, mjd=None, fiberID=None,
348455
47.1604269095 5.48241410994 2340 53733 332 2634697104106219520
349456
48.6634992214 6.69459110287 2340 53733 553 2634757852123654144
350457
48.0759195428 6.18757403485 2340 53733 506 2634744932862027776
351-
352-
Returns
353-
-------
354-
result : `~astropy.table.Table`
355-
The result of the query as an `~astropy.table.Table` object.
356-
357458
"""
358459

359460
if plate is None and mjd is None and fiberID is None:
@@ -415,6 +516,11 @@ def query_photoobj_async(self, *, run=None, rerun=301, camcol=None,
415516
cache : bool, optional
416517
If ``True`` use the request caching mechanism.
417518
519+
Returns
520+
-------
521+
result : `~astropy.table.Table`
522+
The result of the query as a `~astropy.table.Table` object.
523+
418524
Examples
419525
--------
420526
>>> from astroquery.sdss import SDSS
@@ -427,12 +533,6 @@ def query_photoobj_async(self, *, run=None, rerun=301, camcol=None,
427533
22.2574304026 8.43175488904 1237670017262485671 5714 301 6 21
428534
23.3724928784 8.32576993103 1237670017262944491 5714 301 6 28
429535
25.4801226435 8.27642390025 1237670017263927330 5714 301 6 43
430-
431-
Returns
432-
-------
433-
result : `~astropy.table.Table`
434-
The result of the query as a `~astropy.table.Table` object.
435-
436536
"""
437537

438538
if run is None and camcol is None and field is None:
@@ -477,6 +577,11 @@ def query_sql_async(self, sql_query, *, timeout=TIMEOUT,
477577
cache : bool, optional
478578
If ``True`` use the request caching mechanism.
479579
580+
Returns
581+
-------
582+
result : `~astropy.table.Table`
583+
The result of the query as a `~astropy.table.Table` object.
584+
480585
Examples
481586
--------
482587
>>> from astroquery.sdss import SDSS
@@ -497,20 +602,14 @@ class = 'galaxy' \
497602
0.3000027 156.25024 7.6586271 1237658425162858683
498603
0.3000027 256.99461 25.566255 1237661387086693265
499604
0.300003 175.65125 34.37548 1237665128003731630
500-
501-
Returns
502-
-------
503-
result : `~astropy.table.Table`
504-
The result of the query as a `~astropy.table.Table` object.
505-
506605
"""
507606

508607
request_payload = dict(cmd=self.__sanitize_query(sql_query),
509608
format='csv')
510609
if data_release > 11:
511610
request_payload['searchtool'] = 'SQL'
512611

513-
if kwargs.get('get_query_payload'):
612+
if kwargs.get('get_query_payload') or kwargs.get('field_help'):
514613
return request_payload
515614

516615
url = self._get_query_url(data_release)
@@ -870,16 +969,15 @@ def get_spectral_template_async(self, kind='qso', *, timeout=TIMEOUT,
870969
show_progress : bool, optional
871970
If False, do not display download progress.
872971
972+
Returns
973+
-------
974+
list : List of `~astropy.io.fits.HDUList` objects.
975+
873976
Examples
874977
--------
875978
>>> qso = SDSS.get_spectral_template(kind='qso')
876979
>>> Astar = SDSS.get_spectral_template(kind='star_A')
877980
>>> Fstar = SDSS.get_spectral_template(kind='star_F')
878-
879-
Returns
880-
-------
881-
list : List of `~astropy.io.fits.HDUList` objects.
882-
883981
"""
884982

885983
if kind == 'all':

0 commit comments

Comments
 (0)