1
|
|
# Licensed under a 3-clause BSD style license - see LICENSE.rst
|
2
|
1
|
from astropy.table import Table, Column
|
3
|
1
|
import astropy.units as u
|
4
|
1
|
from astropy import coordinates
|
5
|
1
|
import six
|
6
|
1
|
from . import utils
|
7
|
1
|
from . import conf
|
8
|
1
|
from ..utils import commons
|
9
|
1
|
from ..query import BaseQuery
|
10
|
|
|
11
|
|
|
12
|
|
# TODO Add support for server url from JSON cache
|
13
|
1
|
__all__ = ["IrsaDust", "IrsaDustClass"]
|
14
|
|
|
15
|
1
|
EXT_DESC = "E(B-V) Reddening"
|
16
|
1
|
EM_DESC = "100 Micron Emission"
|
17
|
1
|
TEMP_DESC = "Dust Temperature"
|
18
|
|
|
19
|
1
|
INPUT = "input"
|
20
|
1
|
OBJ_NAME = "objname"
|
21
|
1
|
REG_SIZE = "regSize"
|
22
|
1
|
DESC = "desc"
|
23
|
1
|
IMAGE_URL = "imageUrl"
|
24
|
|
|
25
|
1
|
STATISTICS = "statistics"
|
26
|
1
|
REF_PIXEL_VALUE = "refPixelValue"
|
27
|
1
|
REF_COORDINATE = "refCoordinate"
|
28
|
1
|
MEAN_VALUE = "meanValue"
|
29
|
1
|
STD = "std"
|
30
|
1
|
MAX_VALUE = "maxValue"
|
31
|
1
|
MIN_VALUE = "minValue"
|
32
|
1
|
SANDF = "SandF"
|
33
|
1
|
SFD = "SFD"
|
34
|
|
|
35
|
1
|
DATA_IMAGE = "./data/image"
|
36
|
1
|
DATA_TABLE = "./data/table"
|
37
|
|
|
38
|
|
|
39
|
1
|
class IrsaDustClass(BaseQuery):
|
40
|
|
|
41
|
1
|
DUST_SERVICE_URL = conf.server
|
42
|
1
|
TIMEOUT = conf.timeout
|
43
|
1
|
image_type_to_section = {
|
44
|
|
'temperature': 't',
|
45
|
|
'ebv': 'r',
|
46
|
|
'100um': 'e'
|
47
|
|
}
|
48
|
|
|
49
|
1
|
def get_images(self, coordinate, radius=None,
|
50
|
|
image_type=None, timeout=TIMEOUT, get_query_payload=False,
|
51
|
|
show_progress=True):
|
52
|
|
"""
|
53
|
|
A query function that performs a coordinate-based query to acquire
|
54
|
|
Irsa-Dust images.
|
55
|
|
|
56
|
|
Parameters
|
57
|
|
----------
|
58
|
|
coordinate : str
|
59
|
|
Can be either the name of an object or a coordinate string
|
60
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
61
|
|
Examples of acceptable coordinate strings, can be found `here.
|
62
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
63
|
|
radius : str / `~astropy.units.Quantity`, optional
|
64
|
|
The size of the region to include in the dust query, in radian,
|
65
|
|
degree or hour as per format specified by
|
66
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
67
|
|
Defaults to 5 degrees.
|
68
|
|
image_type : str, optional
|
69
|
|
When missing returns for all the images. Otherwise returns only
|
70
|
|
for image of the specified type which must be one of
|
71
|
|
``'temperature'``, ``'ebv'``, ``'100um'``. Defaults to `None`.
|
72
|
|
timeout : int, optional
|
73
|
|
Time limit for establishing successful connection with remote
|
74
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
75
|
|
get_query_payload : bool, optional
|
76
|
|
If `True` then returns the dictionary of query parameters, posted
|
77
|
|
to remote server. Defaults to `False`.
|
78
|
|
|
79
|
|
Returns
|
80
|
|
-------
|
81
|
|
A list of `~astropy.io.fits.HDUList` objects
|
82
|
|
|
83
|
|
"""
|
84
|
|
|
85
|
1
|
if get_query_payload:
|
86
|
0
|
return self._args_to_payload(coordinate, radius=radius)
|
87
|
1
|
readable_objs = self.get_images_async(
|
88
|
|
coordinate, radius=radius, image_type=image_type, timeout=timeout,
|
89
|
|
get_query_payload=get_query_payload, show_progress=show_progress)
|
90
|
1
|
return [obj.get_fits() for obj in readable_objs]
|
91
|
|
|
92
|
1
|
def get_images_async(self, coordinate, radius=None, image_type=None,
|
93
|
|
timeout=TIMEOUT, get_query_payload=False,
|
94
|
|
show_progress=True):
|
95
|
|
"""
|
96
|
|
A query function similar to
|
97
|
|
`astroquery.irsa_dust.IrsaDustClass.get_images` but returns
|
98
|
|
file-handlers to the remote files rather than downloading
|
99
|
|
them. Useful for asynchronous queries so that the actual download
|
100
|
|
may be performed later.
|
101
|
|
|
102
|
|
Parameters
|
103
|
|
----------
|
104
|
|
coordinate : str
|
105
|
|
Can be either the name of an object or a coordinate string
|
106
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
107
|
|
Examples of acceptable coordinate strings, can be found `here.
|
108
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
109
|
|
radius : str / `~astropy.units.Quantity`, optional
|
110
|
|
The size of the region to include in the dust query, in radian,
|
111
|
|
degree or hour as per format specified by
|
112
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
113
|
|
Defaults to 5 degrees.
|
114
|
|
image_type : str, optional
|
115
|
|
When missing returns for all the images. Otherwise returns only
|
116
|
|
for image of the specified type which must be one of
|
117
|
|
``'temperature'``, ``'ebv'``, ``'100um'``. Defaults to `None`.
|
118
|
|
timeout : int, optional
|
119
|
|
Time limit for establishing successful connection with remote
|
120
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
121
|
|
get_query_payload : bool, optional
|
122
|
|
If `True` then returns the dictionary of query parameters, posted
|
123
|
|
to remote server. Defaults to `False`.
|
124
|
|
|
125
|
|
Returns
|
126
|
|
--------
|
127
|
|
list : list
|
128
|
|
A list of context-managers that yield readable file-like objects.
|
129
|
|
"""
|
130
|
|
|
131
|
1
|
if get_query_payload:
|
132
|
0
|
return self._args_to_payload(coordinate, radius=radius)
|
133
|
1
|
image_urls = self.get_image_list(
|
134
|
|
coordinate, radius=radius, image_type=image_type, timeout=timeout)
|
135
|
|
|
136
|
|
# Images are assumed to be FITS files
|
137
|
|
# they MUST be read as binary for python3 to parse them
|
138
|
1
|
return [commons.FileContainer(U, encoding='binary',
|
139
|
|
show_progress=show_progress)
|
140
|
|
for U in image_urls]
|
141
|
|
|
142
|
1
|
def get_image_list(self, coordinate, radius=None, image_type=None,
|
143
|
|
timeout=TIMEOUT):
|
144
|
|
"""
|
145
|
|
Query function that performs coordinate-based query and returns a list
|
146
|
|
of URLs to the Irsa-Dust images.
|
147
|
|
|
148
|
|
Parameters
|
149
|
|
-----------
|
150
|
|
coordinate : str
|
151
|
|
Can be either the name of an object or a coordinate string
|
152
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
153
|
|
Examples of acceptable coordinate strings, can be found `here.
|
154
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
155
|
|
radius : str / `~astropy.units.Quantity`, optional
|
156
|
|
The size of the region to include in the dust query, in radian,
|
157
|
|
degree or hour as per format specified by
|
158
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
159
|
|
Defaults to 5 degrees.
|
160
|
|
image_type : str, optional
|
161
|
|
When missing returns for all the images. Otherwise returns only
|
162
|
|
for image of the specified type which must be one of
|
163
|
|
``'temperature'``, ``'ebv'``, ``'100um'``. Defaults to `None`.
|
164
|
|
timeout : int, optional
|
165
|
|
Time limit for establishing successful connection with remote
|
166
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
167
|
|
get_query_payload : bool
|
168
|
|
If `True` then returns the dictionary of query parameters, posted
|
169
|
|
to remote server. Defaults to `False`.
|
170
|
|
|
171
|
|
Returns
|
172
|
|
--------
|
173
|
|
url_list : list
|
174
|
|
A list of URLs to the FITS images corresponding to the queried
|
175
|
|
object.
|
176
|
|
"""
|
177
|
1
|
url = self.DUST_SERVICE_URL
|
178
|
1
|
request_payload = self._args_to_payload(coordinate, radius=radius)
|
179
|
1
|
response = self._request("POST", url, data=request_payload,
|
180
|
|
timeout=timeout)
|
181
|
1
|
return self.extract_image_urls(response.text, image_type=image_type)
|
182
|
|
|
183
|
1
|
def get_extinction_table(self, coordinate, radius=None, timeout=TIMEOUT,
|
184
|
|
show_progress=True):
|
185
|
|
"""
|
186
|
|
Query function that fetches the extinction table from the query
|
187
|
|
result.
|
188
|
|
|
189
|
|
Parameters
|
190
|
|
----------
|
191
|
|
coordinate : str
|
192
|
|
Can be either the name of an object or a coordinate string
|
193
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
194
|
|
Examples of acceptable coordinate strings, can be found `here.
|
195
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
196
|
|
radius : str / `~astropy.units.Quantity`, optional
|
197
|
|
The size of the region to include in the dust query, in radian,
|
198
|
|
degree or hour as per format specified by
|
199
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
200
|
|
Defaults to 5 degrees.
|
201
|
|
timeout : int, optional
|
202
|
|
Time limit for establishing successful connection with remote
|
203
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
204
|
|
|
205
|
|
Returns
|
206
|
|
--------
|
207
|
|
table : `~astropy.table.Table`
|
208
|
|
"""
|
209
|
1
|
readable_obj = self.get_extinction_table_async(
|
210
|
|
coordinate, radius=radius, timeout=timeout,
|
211
|
|
show_progress=show_progress)
|
212
|
|
# guess=False to suppress error messages related to bad guesses
|
213
|
1
|
table = Table.read(readable_obj.get_string(), format='ipac',
|
214
|
|
guess=False)
|
215
|
|
# Fix up units: 'micron' and 'mag', not 'microns' and 'mags'
|
216
|
1
|
for column in table.columns.values():
|
217
|
1
|
if str(column.unit) in {'microns', 'mags'}:
|
218
|
1
|
column.unit = str(column.unit)[:-1]
|
219
|
1
|
return table
|
220
|
|
|
221
|
1
|
def get_extinction_table_async(self, coordinate, radius=None,
|
222
|
|
timeout=TIMEOUT, show_progress=True):
|
223
|
|
"""
|
224
|
|
A query function similar to
|
225
|
|
`astroquery.irsa_dust.IrsaDustClass.get_extinction_table` but
|
226
|
|
returns a file-handler to the remote files rather than downloading
|
227
|
|
it. Useful for asynchronous queries so that the actual download may
|
228
|
|
be performed later.
|
229
|
|
|
230
|
|
Parameters
|
231
|
|
----------
|
232
|
|
coordinate : str
|
233
|
|
Can be either the name of an object or a coordinate string
|
234
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
235
|
|
Examples of acceptable coordinate strings, can be found `here.
|
236
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
237
|
|
radius : str, optional
|
238
|
|
The size of the region to include in the dust query, in radian,
|
239
|
|
degree or hour as per format specified by
|
240
|
|
`~astropy.coordinates.Angle`. Defaults to 5 degrees.
|
241
|
|
timeout : int, optional
|
242
|
|
Time limit for establishing successful connection with remote
|
243
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
244
|
|
|
245
|
|
Returns
|
246
|
|
-------
|
247
|
|
result : A context manager that yields a file like readable object.
|
248
|
|
"""
|
249
|
1
|
url = self.DUST_SERVICE_URL
|
250
|
1
|
request_payload = self._args_to_payload(coordinate, radius=radius)
|
251
|
1
|
response = self._request("POST", url, data=request_payload,
|
252
|
|
timeout=timeout)
|
253
|
1
|
xml_tree = utils.xml(response.text)
|
254
|
1
|
result = SingleDustResult(xml_tree, coordinate)
|
255
|
1
|
return commons.FileContainer(result.ext_detail_table(),
|
256
|
|
show_progress=show_progress)
|
257
|
|
|
258
|
1
|
def get_query_table(self, coordinate, radius=None,
|
259
|
|
section=None, timeout=TIMEOUT, url=DUST_SERVICE_URL):
|
260
|
|
"""
|
261
|
|
Create and return an `~astropy.table.Table` representing the query
|
262
|
|
response(s).
|
263
|
|
|
264
|
|
When ``section`` is missing, returns the full table. When a
|
265
|
|
section is specified (``'location'``, ``'temperature'``, ``'ebv'``, or
|
266
|
|
``'100um'``), only that portion of the table is returned.
|
267
|
|
|
268
|
|
Parameters
|
269
|
|
----------
|
270
|
|
coordinate : str
|
271
|
|
Can be either the name of an object or a coordinate string
|
272
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
273
|
|
Examples of acceptable coordinate strings, can be found `here.
|
274
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
275
|
|
radius : str / `~astropy.units.Quantity`, optional
|
276
|
|
The size of the region to include in the dust query, in radian,
|
277
|
|
degree or hour as per format specified by
|
278
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
279
|
|
Defaults to 5 degrees.
|
280
|
|
section : str, optional
|
281
|
|
When missing, all the sections of the query result are returned.
|
282
|
|
Otherwise only the specified section (``'ebv'``, ``'100um'``,
|
283
|
|
``'temperature'``, ``'location'``) is returned. Defaults to `None`.
|
284
|
|
timeout : int, optional
|
285
|
|
Time limit for establishing successful connection with remote
|
286
|
|
server. Defaults to `~astroquery.irsa_dust.IrsaDustClass.TIMEOUT`.
|
287
|
|
url : str, optional
|
288
|
|
Only provided for debugging. Should generally not be assigned.
|
289
|
|
Defaults to `~astroquery.irsa_dust.IrsaDustClass.DUST_SERVICE_URL`.
|
290
|
|
|
291
|
|
Returns
|
292
|
|
--------
|
293
|
|
table : `~astropy.table.Table`
|
294
|
|
Table representing the query results, (all or as per specified).
|
295
|
|
"""
|
296
|
1
|
request_payload = self._args_to_payload(coordinate, radius=radius)
|
297
|
1
|
response = self._request("POST", url, data=request_payload,
|
298
|
|
timeout=timeout)
|
299
|
1
|
xml_tree = utils.xml(response.text)
|
300
|
1
|
result = SingleDustResult(xml_tree, coordinate)
|
301
|
1
|
if section is None or section in ["location", "loc", "l"]:
|
302
|
1
|
return result.table(section=section)
|
303
|
1
|
try:
|
304
|
1
|
section = self.image_type_to_section[section]
|
305
|
1
|
return result.table(section=section)
|
306
|
0
|
except KeyError:
|
307
|
0
|
msg = ('section must be one of the following:\n'
|
308
|
|
'ebv, temperature, location or 100um.')
|
309
|
0
|
raise ValueError(msg)
|
310
|
|
|
311
|
1
|
def _args_to_payload(self, coordinate, radius=None):
|
312
|
|
"""
|
313
|
|
Accepts the query parameters and returns a dictionary
|
314
|
|
suitable to be sent as data via a HTTP POST request.
|
315
|
|
|
316
|
|
Parameters
|
317
|
|
----------
|
318
|
|
coordinate : str
|
319
|
|
Can be either the name of an object or a coordinate string
|
320
|
|
If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
|
321
|
|
Examples of acceptable coordinate strings, can be found `here
|
322
|
|
<https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
|
323
|
|
radius : str / `~astropy.units.Quantity`, optional
|
324
|
|
The size of the region to include in the dust query, in radian,
|
325
|
|
degree or hour as per format specified by
|
326
|
|
`~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
|
327
|
|
Defaults to 5 degrees.
|
328
|
|
|
329
|
|
Returns
|
330
|
|
-------
|
331
|
|
payload : dict
|
332
|
|
A dictionary that specifies the data for an HTTP POST request
|
333
|
|
"""
|
334
|
1
|
if isinstance(coordinate, six.string_types):
|
335
|
1
|
try:
|
336
|
|
# If the coordinate is a resolvable name, pass that name
|
337
|
|
# directly to irsa_dust because it can handle it (and that
|
338
|
|
# changes the return value associated metadata)
|
339
|
1
|
C = commons.ICRSCoord.from_name(coordinate)
|
340
|
1
|
payload = {"locstr": coordinate}
|
341
|
0
|
except coordinates.name_resolve.NameResolveError:
|
342
|
0
|
C = commons.parse_coordinates(coordinate).transform_to('fk5')
|
343
|
|
# check if this is resolvable?
|
344
|
0
|
payload = {"locstr": "{0} {1}".format(C.ra.deg, C.dec.deg)}
|
345
|
1
|
elif isinstance(coordinate, coordinates.SkyCoord):
|
346
|
1
|
C = coordinate.transform_to('fk5')
|
347
|
1
|
payload = {"locstr": "{0} {1}".format(C.ra.deg, C.dec.deg)}
|
348
|
|
# check if radius is given with proper units
|
349
|
1
|
if radius is not None:
|
350
|
1
|
reg_size = coordinates.Angle(radius).deg
|
351
|
|
# check if radius falls in the acceptable range
|
352
|
1
|
if reg_size < 2 or reg_size > 37.5:
|
353
|
1
|
raise ValueError("Radius (in any unit) must be in the"
|
354
|
|
" range of 2.0 to 37.5 degrees")
|
355
|
1
|
payload["regSize"] = reg_size
|
356
|
1
|
return payload
|
357
|
|
|
358
|
1
|
def extract_image_urls(self, raw_xml, image_type=None):
|
359
|
|
"""
|
360
|
|
Extracts the image URLs from the query results and
|
361
|
|
returns these as a list. If section is missing or
|
362
|
|
``'all'`` returns all the URLs, otherwise returns URL
|
363
|
|
corresponding to the section specified (``'emission'``,
|
364
|
|
``'reddening'``, ``'temperature'``).
|
365
|
|
|
366
|
|
Parameters
|
367
|
|
----------
|
368
|
|
raw_xml : str
|
369
|
|
XML response returned by the query as a string
|
370
|
|
image_type : str, optional
|
371
|
|
When missing returns for all the images. Otherwise returns only
|
372
|
|
for image of the specified type which must be one of
|
373
|
|
``'temperature'``, ``'ebv'``, ``'100um'``. Defaults to `None`.
|
374
|
|
|
375
|
|
Returns
|
376
|
|
-------
|
377
|
|
url_list : list
|
378
|
|
list of URLs to images extracted from query results.
|
379
|
|
"""
|
380
|
|
# get the xml tree from the response
|
381
|
1
|
xml_tree = utils.xml(raw_xml)
|
382
|
1
|
result = SingleDustResult(xml_tree)
|
383
|
1
|
if image_type is None:
|
384
|
1
|
url_list = [result.image(sec) for sec in
|
385
|
|
['r', 'e', 't']]
|
386
|
|
else:
|
387
|
1
|
try:
|
388
|
1
|
section = self.image_type_to_section[image_type]
|
389
|
1
|
url_list = [result.image(section)]
|
390
|
1
|
except KeyError:
|
391
|
1
|
msg = ('image_type must be one of the following:\n'
|
392
|
|
'ebv, temperature or 100um.')
|
393
|
1
|
raise ValueError(msg)
|
394
|
1
|
return url_list
|
395
|
|
|
396
|
1
|
def list_image_types(self):
|
397
|
|
"""
|
398
|
|
Returns a list of image_types available in the Irsa Dust
|
399
|
|
query results
|
400
|
|
"""
|
401
|
1
|
return [key for key in self.image_type_to_section]
|
402
|
|
|
403
|
|
|
404
|
1
|
class SingleDustResult(object):
|
405
|
|
|
406
|
|
"""
|
407
|
|
Represents the response to a dust query for a single object or location.
|
408
|
|
|
409
|
|
Provides methods to return the response as an `~astropy.table.Table`,
|
410
|
|
and to retrieve FITS images listed as urls in the initial response. It
|
411
|
|
can also return the url to a detailed extinction table provided in the
|
412
|
|
initial response. Not intended to be instantiated by the end user.
|
413
|
|
"""
|
414
|
|
|
415
|
1
|
def __init__(self, xml_tree, query_loc=None):
|
416
|
|
"""
|
417
|
|
Parameters
|
418
|
|
----------
|
419
|
|
xml_root : `xml.etree.ElementTree`
|
420
|
|
the xml tree representing the response to the query
|
421
|
|
query_loc : str
|
422
|
|
the location string specified in the query
|
423
|
|
"""
|
424
|
1
|
self._xml = xml_tree
|
425
|
1
|
self._query_loc = query_loc
|
426
|
|
|
427
|
1
|
self._location_section = LocationSection(xml_tree)
|
428
|
|
|
429
|
1
|
ext_node = utils.find_result_node(EXT_DESC, xml_tree)
|
430
|
1
|
self._ext_section = ExtinctionSection(ext_node)
|
431
|
|
|
432
|
1
|
em_node = utils.find_result_node(EM_DESC, xml_tree)
|
433
|
1
|
self._em_section = EmissionSection(em_node)
|
434
|
|
|
435
|
1
|
temp_node = utils.find_result_node(TEMP_DESC, xml_tree)
|
436
|
1
|
self._temp_section = TemperatureSection(temp_node)
|
437
|
|
|
438
|
1
|
self._result_sections = [self._location_section, self._ext_section,
|
439
|
|
self._em_section, self._temp_section]
|
440
|
|
|
441
|
1
|
@property
|
442
|
|
def query_loc(self):
|
443
|
|
"""Return the location string used in the query."""
|
444
|
0
|
return self._query_loc
|
445
|
|
|
446
|
1
|
@property
|
447
|
|
def xml(self):
|
448
|
|
"""Return the raw xml underlying this SingleDustResult."""
|
449
|
0
|
return self._xml
|
450
|
|
|
451
|
1
|
def table(self, section=None):
|
452
|
|
"""
|
453
|
|
Create and return a `~astropy.table.Table` representing the query
|
454
|
|
response.
|
455
|
|
|
456
|
|
Parameters
|
457
|
|
----------
|
458
|
|
section : str
|
459
|
|
(optional) the name of the section to include in the table.
|
460
|
|
If not provided, the entire table will be returned.
|
461
|
|
"""
|
462
|
1
|
code = self._section_code(section)
|
463
|
1
|
if code == "all":
|
464
|
1
|
return self._table_all()
|
465
|
|
else:
|
466
|
1
|
return self._table(code)
|
467
|
|
|
468
|
1
|
def values(self, section=None):
|
469
|
|
"""
|
470
|
|
Return the data values contained in the query response,
|
471
|
|
i.e. the list of values corresponding to a row in the result table.
|
472
|
|
|
473
|
|
Parameters
|
474
|
|
----------
|
475
|
|
section : str
|
476
|
|
the name of the section to include in the response
|
477
|
|
If no section is given, all sections will be included.
|
478
|
|
"""
|
479
|
1
|
code = self._section_code(section)
|
480
|
1
|
sections = self._sections(code)
|
481
|
|
|
482
|
1
|
values = []
|
483
|
1
|
for sec in sections:
|
484
|
1
|
values.extend(sec.values())
|
485
|
1
|
return values
|
486
|
|
|
487
|
1
|
def _section_code(self, section):
|
488
|
|
"""
|
489
|
|
Return a one-letter code identifying the section.
|
490
|
|
|
491
|
|
Parameters
|
492
|
|
----------
|
493
|
|
section : str
|
494
|
|
the name or abbreviated name of the section
|
495
|
|
|
496
|
|
Returns
|
497
|
|
-------
|
498
|
|
str: a one-letter code identifying the section.
|
499
|
|
"""
|
500
|
1
|
if section is None or section == "all":
|
501
|
1
|
return "all"
|
502
|
|
else:
|
503
|
1
|
if section in ["location", "loc", "l"]:
|
504
|
1
|
return "l"
|
505
|
1
|
elif section in ["reddening", "red", "r"]:
|
506
|
1
|
return "r"
|
507
|
1
|
elif section in ["emission", "em", "e"]:
|
508
|
1
|
return "e"
|
509
|
1
|
elif section in ["temperature", "temp", "t"]:
|
510
|
1
|
return "t"
|
511
|
|
else:
|
512
|
0
|
msg = """section must be one of the following:
|
513
|
|
'all',
|
514
|
|
'location', 'loc', 'l',
|
515
|
|
'reddening', 'red', 'r',
|
516
|
|
'emission', 'em', 'e',
|
517
|
|
'temperature', 'temp', 't'."""
|
518
|
0
|
raise ValueError(msg)
|
519
|
|
|
520
|
1
|
def _sections(self, code):
|
521
|
|
"""
|
522
|
|
Parameters
|
523
|
|
----------
|
524
|
|
code : str
|
525
|
|
the one-letter code name of the section
|
526
|
|
|
527
|
|
Returns
|
528
|
|
-------
|
529
|
|
The section corresponding to the code, or a list containing all
|
530
|
|
sections if no section is provided.
|
531
|
|
"""
|
532
|
1
|
if code == 'l':
|
533
|
1
|
return [self._location_section]
|
534
|
1
|
elif code == 'r':
|
535
|
1
|
return [self._ext_section]
|
536
|
1
|
elif code == 'e':
|
537
|
1
|
return [self._em_section]
|
538
|
1
|
elif code == 't':
|
539
|
1
|
return [self._temp_section]
|
540
|
1
|
return [self._location_section, self._ext_section, self._em_section,
|
541
|
|
self._temp_section]
|
542
|
|
|
543
|
1
|
def _table_all(self):
|
544
|
|
"""
|
545
|
|
Create and return the full table containing all four sections:
|
546
|
|
location, extinction, emission, and temperature.
|
547
|
|
|
548
|
|
Returns
|
549
|
|
-------
|
550
|
|
table : `~astropy.table.Table`
|
551
|
|
table containing the data from the query response
|
552
|
|
"""
|
553
|
1
|
columns = (self._location_section.columns + self._ext_section.columns +
|
554
|
|
self._em_section.columns + self._temp_section.columns)
|
555
|
1
|
table = Table(data=columns)
|
556
|
|
|
557
|
1
|
values = self.values()
|
558
|
1
|
table.add_row(vals=values)
|
559
|
1
|
return table
|
560
|
|
|
561
|
1
|
def _table(self, section):
|
562
|
|
"""
|
563
|
|
Create and return a smaller table containing only one section
|
564
|
|
of the overall DustResult table.
|
565
|
|
|
566
|
|
Parameters
|
567
|
|
----------
|
568
|
|
section : str
|
569
|
|
a string indicating the section to be returned
|
570
|
|
"""
|
571
|
|
# Get the specified section
|
572
|
1
|
section_object = self._sections(section)[0]
|
573
|
|
|
574
|
|
# Create the table
|
575
|
1
|
columns = section_object.columns
|
576
|
1
|
table = Table(data=columns)
|
577
|
|
|
578
|
|
# Populate the table
|
579
|
1
|
values = section_object.values()
|
580
|
1
|
table.add_row(vals=values)
|
581
|
|
|
582
|
1
|
return table
|
583
|
|
|
584
|
1
|
def ext_detail_table(self):
|
585
|
|
"""
|
586
|
|
Get the url of the additional, detailed table of extinction data for
|
587
|
|
various filters. There is a url for this table given in the initial
|
588
|
|
response to the query.
|
589
|
|
|
590
|
|
Returns
|
591
|
|
-------
|
592
|
|
table_url : str
|
593
|
|
url of the detailed table of extinction data by filter
|
594
|
|
"""
|
595
|
1
|
table_url = self._ext_section.table_url
|
596
|
|
# response = utils.ext_detail_table(table_url)
|
597
|
|
# if sys.version_info > (3, 0):
|
598
|
|
# read_response = response.read().decode("utf-8")
|
599
|
|
# else:
|
600
|
|
# read_response = response.read()
|
601
|
|
# table = Table.read(read_response, format="ipac")
|
602
|
|
# return table
|
603
|
1
|
return table_url
|
604
|
|
|
605
|
1
|
def image(self, section):
|
606
|
|
"""
|
607
|
|
Get the FITS image url associated with the given section.
|
608
|
|
The extinction, emission, and temperature sections each provide
|
609
|
|
a url to a FITS image.
|
610
|
|
|
611
|
|
Parameters
|
612
|
|
----------
|
613
|
|
section : str
|
614
|
|
the name of the section
|
615
|
|
|
616
|
|
Returns
|
617
|
|
-------
|
618
|
|
url : str
|
619
|
|
the url to the FITS image
|
620
|
|
"""
|
621
|
|
# Get the url of the image for the given section
|
622
|
1
|
image_url = None
|
623
|
1
|
if section in ["reddening", "red", "r"]:
|
624
|
1
|
image_url = self._ext_section.image_url
|
625
|
1
|
elif section in ["emission", "em", "e"]:
|
626
|
1
|
image_url = self._em_section.image_url
|
627
|
1
|
elif section in ["temperature", "temp", "t"]:
|
628
|
1
|
image_url = self._temp_section.image_url
|
629
|
|
|
630
|
1
|
if image_url is None:
|
631
|
0
|
msg = """section must be one of the following values:
|
632
|
|
'reddening', 'red', 'r',
|
633
|
|
'emission', 'em', 'e',
|
634
|
|
'temperature', 'temp', 't'"""
|
635
|
0
|
raise ValueError(msg)
|
636
|
|
|
637
|
1
|
return image_url
|
638
|
|
|
639
|
1
|
def __str__(self):
|
640
|
|
"""Return a string representation of the table."""
|
641
|
0
|
string = "[DustResult: \n\t"
|
642
|
0
|
for section in self._result_sections:
|
643
|
0
|
if len(string) > 15:
|
644
|
0
|
string += ",\n\t"
|
645
|
0
|
string += section.__str__()
|
646
|
0
|
string += "]"
|
647
|
0
|
return string
|
648
|
|
|
649
|
|
|
650
|
1
|
class BaseDustNode(object):
|
651
|
|
|
652
|
|
"""
|
653
|
|
A node in the result xml that has been enhanced to return values and
|
654
|
|
Columns appropriate to its type (String, Number, or Coord).
|
655
|
|
"""
|
656
|
|
|
657
|
1
|
def __init__(self, xml_node):
|
658
|
|
"""
|
659
|
|
Parameters
|
660
|
|
----------
|
661
|
|
xml_node : `xml.etree.ElementTree`
|
662
|
|
the xml node that provides the raw data for this DustNode
|
663
|
|
"""
|
664
|
1
|
self._name = xml_node.tag
|
665
|
|
|
666
|
1
|
def set_value(self, node_text):
|
667
|
|
"""Override in subclasses."""
|
668
|
0
|
pass
|
669
|
|
|
670
|
1
|
@property
|
671
|
|
def name(self):
|
672
|
|
"""Return the xml node name."""
|
673
|
0
|
return self._name
|
674
|
|
|
675
|
1
|
@property
|
676
|
|
def value(self):
|
677
|
|
"""Return the value extracted from the node."""
|
678
|
0
|
return self._value
|
679
|
|
|
680
|
1
|
@property
|
681
|
|
def columns(self):
|
682
|
|
"""Return the column or columns associated with this item in the
|
683
|
|
`~astropy.table.Table`."""
|
684
|
0
|
return self._columns
|
685
|
|
|
686
|
1
|
def __str__(self):
|
687
|
|
"""Return a string representation of this item."""
|
688
|
0
|
col_str = "[Column: "
|
689
|
0
|
for column in self._columns:
|
690
|
0
|
for format_str in column.pformat(show_units=True):
|
691
|
0
|
col_str += format_str
|
692
|
0
|
string = "name: " + self._name + ", " + col_str + "]"
|
693
|
0
|
return string
|
694
|
|
|
695
|
|
|
696
|
1
|
class StringNode(BaseDustNode):
|
697
|
|
|
698
|
|
"""
|
699
|
|
A node that contains text.
|
700
|
|
"""
|
701
|
|
|
702
|
1
|
def __init__(self, xml_node, col_name, length):
|
703
|
|
"""
|
704
|
|
Parameters
|
705
|
|
----------
|
706
|
|
xml_node : `xml.etree.ElementTree`
|
707
|
|
the xml node that provides the raw data for this DustNode
|
708
|
|
col_name : str
|
709
|
|
the name of the column associated with this item
|
710
|
|
length : int
|
711
|
|
the size of the column associated with this item
|
712
|
|
"""
|
713
|
1
|
BaseDustNode.__init__(self, xml_node)
|
714
|
|
|
715
|
1
|
self._value = xml_node.text.strip()
|
716
|
|
|
717
|
1
|
self._length = length
|
718
|
1
|
self._columns = [Column(name=col_name, dtype="S" + str(length))]
|
719
|
|
|
720
|
1
|
def __str__(self):
|
721
|
|
"""Return a string representation of this item."""
|
722
|
0
|
base_string = BaseDustNode.__str__(self)
|
723
|
0
|
string = ("[StringNode: " + base_string +
|
724
|
|
", value: " + self._value + "]")
|
725
|
0
|
return string
|
726
|
|
|
727
|
|
|
728
|
1
|
class NumberNode(BaseDustNode):
|
729
|
|
|
730
|
|
"""
|
731
|
|
A node that contains a number. Outputs a single column containing the
|
732
|
|
number.
|
733
|
|
"""
|
734
|
|
|
735
|
1
|
def __init__(self, xml_node, col_name, units=None):
|
736
|
|
"""
|
737
|
|
Parameters
|
738
|
|
----------
|
739
|
|
xml_node : `xml.etree.ElementTree`
|
740
|
|
the xml node that provides the raw data for this DustNode
|
741
|
|
col_name : str
|
742
|
|
the name of the column associated with this item
|
743
|
|
units : `~astropy.units.Unit`
|
744
|
|
the units associated with this item
|
745
|
|
"""
|
746
|
1
|
BaseDustNode.__init__(self, xml_node)
|
747
|
1
|
self._value = utils.parse_number(xml_node.text)
|
748
|
1
|
self._columns = [Column(name=col_name, unit=units)]
|
749
|
|
|
750
|
1
|
def __str__(self):
|
751
|
|
"""Return a string representation of the item."""
|
752
|
0
|
base_string = BaseDustNode.__str__(self)
|
753
|
|
|
754
|
0
|
string = ("[NumberNode: " + base_string +
|
755
|
|
", value: " + str(self._value) + "]")
|
756
|
0
|
return string
|
757
|
|
|
758
|
|
|
759
|
1
|
class CoordNode(BaseDustNode):
|
760
|
|
|
761
|
|
"""
|
762
|
|
A node that contains RA, Dec coordinates. Outputs three values /
|
763
|
|
columns: RA, Dec and a coordinate system description string.
|
764
|
|
"""
|
765
|
|
|
766
|
1
|
def __init__(self, xml_node, col_names):
|
767
|
|
"""
|
768
|
|
Parameters
|
769
|
|
----------
|
770
|
|
xml_node : `xml.etree.ElementTree`
|
771
|
|
the xml node that provides the raw data for this DustNode
|
772
|
|
col_names : str
|
773
|
|
the names of the columns associated with this item
|
774
|
|
"""
|
775
|
1
|
BaseDustNode.__init__(self, xml_node)
|
776
|
1
|
self._value = utils.parse_coords(xml_node.text)
|
777
|
1
|
units = u.deg
|
778
|
1
|
self._columns = [Column(name=col_names[0], unit=units),
|
779
|
|
Column(name=col_names[1], unit=units),
|
780
|
|
Column(name=col_names[2], dtype="S25")]
|
781
|
|
|
782
|
1
|
def __str__(self):
|
783
|
|
"""Return a string representation of the item."""
|
784
|
0
|
base_string = BaseDustNode.__str__(self)
|
785
|
0
|
values_str = ("values: " + str(self._value[0]) + ", " +
|
786
|
|
str(self._value[1]) + ", " + str(self._value[2]))
|
787
|
0
|
string = ("[CoordNode: " + base_string + ", " + values_str + "]")
|
788
|
0
|
return string
|
789
|
|
|
790
|
|
|
791
|
1
|
class BaseResultSection(object):
|
792
|
|
|
793
|
|
"""
|
794
|
|
Represents a group of related nodes/columns in a DustResults object.
|
795
|
|
A DustResults table contains four main sections:
|
796
|
|
1-location
|
797
|
|
2-extinction
|
798
|
|
3-emission
|
799
|
|
4-temperature
|
800
|
|
In addition, the extinction, emission, and temperature sections
|
801
|
|
each contain a nested statistics subsection.
|
802
|
|
"""
|
803
|
|
|
804
|
1
|
def node_dict(self, names, xml_root):
|
805
|
|
"""
|
806
|
|
Find all the nodes with the given names under the given root,
|
807
|
|
and put them in a dictionary.
|
808
|
|
|
809
|
|
Parameters
|
810
|
|
----------
|
811
|
|
names : list[str]
|
812
|
|
the names of the nodes to find
|
813
|
|
xml_root : `xml.etree.ElementTree`
|
814
|
|
the root of the xml tree to search
|
815
|
|
|
816
|
|
Returns
|
817
|
|
-------
|
818
|
|
nodes : dictionary
|
819
|
|
a dictionary of xml nodes, where the keys are the node names
|
820
|
|
"""
|
821
|
1
|
nodes = {}
|
822
|
1
|
for name in names:
|
823
|
1
|
found_node = xml_root.find(name)
|
824
|
1
|
if found_node is None:
|
825
|
0
|
raise ValueError("Could not find node '" + name + "'")
|
826
|
1
|
nodes[name] = found_node
|
827
|
1
|
return nodes
|
828
|
|
|
829
|
1
|
def create_columns(self):
|
830
|
|
"""Build the columns associated with this section."""
|
831
|
1
|
columns = []
|
832
|
1
|
for dust_node in self._dust_nodes:
|
833
|
1
|
if isinstance(dust_node._columns, list):
|
834
|
1
|
columns.extend(dust_node._columns)
|
835
|
|
else:
|
836
|
0
|
columns.append(dust_node._columns)
|
837
|
1
|
self._columns = columns
|
838
|
|
|
839
|
1
|
@property
|
840
|
|
def columns(self):
|
841
|
|
"""Return the list of columns associated with this section."""
|
842
|
1
|
return self._columns
|
843
|
|
|
844
|
1
|
def values(self):
|
845
|
|
"""Return the list of data values associated with this section,
|
846
|
|
i.e. the data corresponding to a single row in the results table."""
|
847
|
1
|
values = []
|
848
|
1
|
for dust_node in self._dust_nodes:
|
849
|
1
|
if isinstance(dust_node._value, list):
|
850
|
1
|
values.extend(dust_node._value)
|
851
|
|
else:
|
852
|
1
|
values.append(dust_node._value)
|
853
|
1
|
return values
|
854
|
|
|
855
|
1
|
def __str__(self):
|
856
|
|
"""Return a string representation of the section."""
|
857
|
0
|
string = "\n\t\t"
|
858
|
0
|
for dust_node in self._dust_nodes:
|
859
|
0
|
if len(string) > 6:
|
860
|
0
|
string += ",\n\t\t"
|
861
|
0
|
string += dust_node.__str__()
|
862
|
0
|
return string
|
863
|
|
|
864
|
|
|
865
|
1
|
class LocationSection(BaseResultSection):
|
866
|
|
|
867
|
|
"""
|
868
|
|
The location section of the DustResults object.
|
869
|
|
"""
|
870
|
|
|
871
|
1
|
def __init__(self, xml_root):
|
872
|
|
"""
|
873
|
|
Parameters
|
874
|
|
----------
|
875
|
|
xml_root : `xml.etree.ElementTree`
|
876
|
|
the xml tree where the data for this section resides
|
877
|
|
"""
|
878
|
1
|
location_node = xml_root.find(INPUT)
|
879
|
1
|
names = [OBJ_NAME, REG_SIZE]
|
880
|
1
|
xml_nodes = self.node_dict(names, location_node)
|
881
|
|
|
882
|
|
# Create the section's DustNodes
|
883
|
1
|
self._dust_nodes = [CoordNode(
|
884
|
|
xml_nodes[OBJ_NAME], col_names=["RA", "Dec", "coord sys"]),
|
885
|
|
NumberNode(xml_nodes[REG_SIZE], REG_SIZE, u.deg)]
|
886
|
|
|
887
|
1
|
self.create_columns()
|
888
|
|
|
889
|
1
|
def __str__(self):
|
890
|
|
"""Return a string representation of the section."""
|
891
|
0
|
base_string = BaseResultSection.__str__(self)
|
892
|
0
|
string = "[LocationSection: " + base_string + "]"
|
893
|
0
|
return string
|
894
|
|
|
895
|
|
|
896
|
1
|
class StatsSection(BaseResultSection):
|
897
|
|
|
898
|
|
"""
|
899
|
|
The statistics subsection of one of an extinction, emission, or temperature
|
900
|
|
section.
|
901
|
|
"""
|
902
|
|
|
903
|
1
|
def __init__(self, xml_root, col_prefix, suffix=""):
|
904
|
|
"""
|
905
|
|
Parameters
|
906
|
|
----------
|
907
|
|
xml_root : `xml.etree.ElementTree`
|
908
|
|
The xml tree containing the data for this section
|
909
|
|
col_prefix : str
|
910
|
|
the prefix to use in column names for this section
|
911
|
|
suffix : str
|
912
|
|
the suffix that appears in the node names (e.g. 'SandF' or 'SDF')
|
913
|
|
"""
|
914
|
|
|
915
|
1
|
names = [
|
916
|
|
REF_PIXEL_VALUE + suffix,
|
917
|
|
REF_COORDINATE,
|
918
|
|
MEAN_VALUE + suffix,
|
919
|
|
STD + suffix,
|
920
|
|
MAX_VALUE + suffix,
|
921
|
|
MIN_VALUE + suffix]
|
922
|
1
|
xml_nodes = self.node_dict(names, xml_root)
|
923
|
|
|
924
|
|
# Create the DustNodes
|
925
|
1
|
self._dust_nodes = [
|
926
|
|
NumberNode(xml_nodes[REF_PIXEL_VALUE + suffix],
|
927
|
|
col_prefix + " ref"),
|
928
|
|
CoordNode(xml_nodes[REF_COORDINATE],
|
929
|
|
col_names=[col_prefix + " ref RA",
|
930
|
|
col_prefix + " ref Dec",
|
931
|
|
col_prefix + " ref coord sys"]),
|
932
|
|
NumberNode(xml_nodes[MEAN_VALUE + suffix], col_prefix + " mean"),
|
933
|
|
NumberNode(xml_nodes[STD + suffix], col_prefix + " std"),
|
934
|
|
NumberNode(xml_nodes[MAX_VALUE + suffix], col_prefix + " max"),
|
935
|
|
NumberNode(xml_nodes[MIN_VALUE + suffix], col_prefix + " min")]
|
936
|
|
|
937
|
1
|
self._units = utils.parse_units(
|
938
|
|
xml_nodes[REF_PIXEL_VALUE + suffix].text)
|
939
|
1
|
self.create_columns()
|
940
|
|
|
941
|
1
|
@property
|
942
|
|
def units(self):
|
943
|
|
"""Return the units associated with this section."""
|
944
|
0
|
return self._units
|
945
|
|
|
946
|
1
|
@property
|
947
|
|
def dust_nodes(self):
|
948
|
|
"""Return the list of DustNodes in this section."""
|
949
|
0
|
return self._dust_nodes
|
950
|
|
|
951
|
1
|
def __str__(self):
|
952
|
|
"""Return a string representation of the section."""
|
953
|
0
|
base_string = "\n\t\t\t\t"
|
954
|
0
|
for dust_node in self._dust_nodes:
|
955
|
0
|
if len(base_string) > 6:
|
956
|
0
|
base_string += ",\n\t\t\t\t"
|
957
|
0
|
base_string += dust_node.__str__()
|
958
|
0
|
string = "\n\t\t\t[StatisticsSection: " + base_string + "]"
|
959
|
0
|
return string
|
960
|
|
|
961
|
|
|
962
|
1
|
class ExtinctionSection(BaseResultSection):
|
963
|
|
|
964
|
|
"""
|
965
|
|
The extinction (reddening) section in a DustResults object.
|
966
|
|
"""
|
967
|
|
|
968
|
1
|
def __init__(self, xml_root):
|
969
|
|
"""
|
970
|
|
Parameters
|
971
|
|
----------
|
972
|
|
xml_root : `xml.etree.ElementTree`
|
973
|
|
The xml tree containing the data for this section
|
974
|
|
"""
|
975
|
|
# Find the section's xml nodes
|
976
|
1
|
names = [DESC, DATA_IMAGE, DATA_TABLE, STATISTICS]
|
977
|
1
|
xml_nodes = self.node_dict(names, xml_root)
|
978
|
|
|
979
|
|
# Build the DustNodes
|
980
|
1
|
self._dust_nodes = [StringNode(xml_nodes[DESC], "ext desc", 100),
|
981
|
|
StringNode(xml_nodes[DATA_IMAGE],
|
982
|
|
"ext image", 255),
|
983
|
|
StringNode(xml_nodes[DATA_TABLE],
|
984
|
|
"ext table", 255)]
|
985
|
|
|
986
|
|
# Create statistics subsections
|
987
|
1
|
self._stats_sandf = StatsSection(xml_nodes[STATISTICS],
|
988
|
|
"ext SandF", "SandF")
|
989
|
1
|
self._stats_sfd = StatsSection(xml_nodes[STATISTICS], "ext SFD", "SFD")
|
990
|
|
|
991
|
1
|
self.create_columns()
|
992
|
|
|
993
|
1
|
def create_columns(self):
|
994
|
|
"""Build the columns associated with this section."""
|
995
|
1
|
BaseResultSection.create_columns(self)
|
996
|
1
|
self._columns.extend(self._stats_sandf.columns)
|
997
|
1
|
self._columns.extend(self._stats_sfd.columns)
|
998
|
|
|
999
|
1
|
@property
|
1000
|
|
def table_url(self):
|
1001
|
|
"""Return the url where the extinction detail table can be found."""
|
1002
|
1
|
table_url = self._dust_nodes[2]._value
|
1003
|
1
|
return table_url
|
1004
|
|
|
1005
|
1
|
@property
|
1006
|
|
def image_url(self):
|
1007
|
|
"""Return the url of the FITS image associated with this section."""
|
1008
|
1
|
return self._dust_nodes[1]._value
|
1009
|
|
|
1010
|
1
|
def values(self):
|
1011
|
|
"""Return the data values associated with this section, i.e. the
|
1012
|
|
list of values corresponding to a single row in the results
|
1013
|
|
table."""
|
1014
|
1
|
ext_values = BaseResultSection.values(self)
|
1015
|
1
|
ext_values.extend(self._stats_sandf.values())
|
1016
|
1
|
ext_values.extend(self._stats_sfd.values())
|
1017
|
1
|
return ext_values
|
1018
|
|
|
1019
|
1
|
def __str__(self):
|
1020
|
|
"""Return a string representation of the section."""
|
1021
|
0
|
base_string = BaseResultSection.__str__(self)
|
1022
|
0
|
string = ("[ExtinctionSection: " + base_string +
|
1023
|
|
self._stats_sandf.__str__() +
|
1024
|
|
self._stats_sfd.__str__() + "]")
|
1025
|
|
|
1026
|
0
|
return string
|
1027
|
|
|
1028
|
|
|
1029
|
1
|
class EmissionSection(BaseResultSection):
|
1030
|
|
|
1031
|
|
"""
|
1032
|
|
The emission section in a DustResults object.
|
1033
|
|
"""
|
1034
|
|
|
1035
|
1
|
def __init__(self, xml_root):
|
1036
|
|
"""
|
1037
|
|
Parameters
|
1038
|
|
----------
|
1039
|
|
xml_root : `xml.etree.ElementTree`
|
1040
|
|
The xml tree containing the data for this section
|
1041
|
|
"""
|
1042
|
1
|
names = [DESC, DATA_IMAGE, STATISTICS]
|
1043
|
1
|
xml_nodes = self.node_dict(names, xml_root)
|
1044
|
|
|
1045
|
|
# Create the DustNodes
|
1046
|
1
|
self._dust_nodes = [StringNode(xml_nodes[DESC], "em desc", 100),
|
1047
|
|
StringNode(xml_nodes[DATA_IMAGE], "em image", 255)]
|
1048
|
|
|
1049
|
|
# Create the statistics subsection
|
1050
|
1
|
self._stats = StatsSection(xml_nodes[STATISTICS], "em")
|
1051
|
|
|
1052
|
1
|
self.create_columns()
|
1053
|
|
|
1054
|
1
|
def create_columns(self):
|
1055
|
|
"""Build the columns associated with this section."""
|
1056
|
1
|
BaseResultSection.create_columns(self)
|
1057
|
1
|
self._columns.extend(self._stats.columns)
|
1058
|
|
|
1059
|
1
|
def values(self):
|
1060
|
|
"""Return the data values associated with this section, i.e. the
|
1061
|
|
list of values corresponding to a single row in the results table."""
|
1062
|
1
|
values = BaseResultSection.values(self)
|
1063
|
1
|
values.extend(self._stats.values())
|
1064
|
1
|
return values
|
1065
|
|
|
1066
|
1
|
@property
|
1067
|
|
def image_url(self):
|
1068
|
|
"""Return the url of the FITS image associated with this section."""
|
1069
|
1
|
return self._dust_nodes[1]._value
|
1070
|
|
|
1071
|
1
|
def __str__(self):
|
1072
|
|
"""Return a string representation of the section."""
|
1073
|
0
|
base_string = BaseResultSection.__str__(self)
|
1074
|
0
|
string = "[EmissionSection: " + \
|
1075
|
|
base_string + self._stats.__str__() + "]"
|
1076
|
0
|
return string
|
1077
|
|
|
1078
|
|
|
1079
|
1
|
IrsaDust = IrsaDustClass()
|
1080
|
|
|
1081
|
|
|
1082
|
1
|
class TemperatureSection(BaseResultSection):
|
1083
|
|
|
1084
|
|
"""
|
1085
|
|
The temperature section in a DustResults object.
|
1086
|
|
"""
|
1087
|
|
|
1088
|
1
|
def __init__(self, xml_root):
|
1089
|
|
"""
|
1090
|
|
Parameters
|
1091
|
|
----------
|
1092
|
|
xml_root : `xml.etree.ElementTree`
|
1093
|
|
The xml tree containing the data for this section
|
1094
|
|
"""
|
1095
|
1
|
names = [DESC, DATA_IMAGE, STATISTICS]
|
1096
|
1
|
xml_nodes = self.node_dict(names, xml_root)
|
1097
|
|
|
1098
|
|
# Create the DustNodes
|
1099
|
1
|
self._dust_nodes = [StringNode(xml_nodes[DESC], "temp desc", 100),
|
1100
|
|
StringNode(xml_nodes[DATA_IMAGE],
|
1101
|
|
"temp image", 255)]
|
1102
|
|
|
1103
|
|
# Create the statistics subsection
|
1104
|
1
|
self._stats = StatsSection(xml_nodes[STATISTICS], "temp")
|
1105
|
|
|
1106
|
1
|
self.create_columns()
|
1107
|
|
|
1108
|
1
|
def create_columns(self):
|
1109
|
|
"""Build the columns associated with this section."""
|
1110
|
1
|
BaseResultSection.create_columns(self)
|
1111
|
1
|
self._columns.extend(self._stats.columns)
|
1112
|
|
|
1113
|
1
|
def values(self):
|
1114
|
|
"""Return the data values associated with this section, i.e. the
|
1115
|
|
list of values corresponding to a single row in the results
|
1116
|
|
table."""
|
1117
|
1
|
values = BaseResultSection.values(self)
|
1118
|
1
|
values.extend(self._stats.values())
|
1119
|
1
|
return values
|
1120
|
|
|
1121
|
1
|
@property
|
1122
|
|
def image_url(self):
|
1123
|
|
"""Return the url of the FITS image associated with this section."""
|
1124
|
1
|
return self._dust_nodes[1]._value
|
1125
|
|
|
1126
|
1
|
def __str__(self):
|
1127
|
|
"""Return a string representation of the section."""
|
1128
|
0
|
base_string = BaseResultSection.__str__(self)
|
1129
|
0
|
string = "[TemperatureSection: " + \
|
1130
|
|
base_string + self._stats.__str__() + "]"
|
1131
|
0
|
return string
|