sparclclient 1.2.0b3.dev9__py3-none-any.whl → 1.2.0b4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sparcl/Results.py CHANGED
@@ -62,7 +62,7 @@ class Results(UserList):
62
62
  else:
63
63
  new = self.fields._science_name(orig, dr)
64
64
  if new is None:
65
- keep = False
65
+ keep = False # We don't have name mapping, toss rec
66
66
  newrec[new] = rec[orig]
67
67
  if keep:
68
68
  newrecs.append(_AttrDict(newrec))
sparcl/__init__.py CHANGED
@@ -31,4 +31,4 @@ __all__ = ["client", "align_records"]
31
31
  #__version__ = '1.1rc1'
32
32
  #__version__ = '1.1rc2'
33
33
  #__version__ = '1.1'
34
- __version__ = '1.2.0b3.dev9'
34
+ __version__ = '1.2.0b4'
sparcl/client.py CHANGED
@@ -130,7 +130,7 @@ class SparclClient(): # was SparclApi()
130
130
 
131
131
  """
132
132
 
133
- KNOWN_GOOD_API_VERSION = 8.0 # @@@ Change this on Server version increment
133
+ KNOWN_GOOD_API_VERSION = 9.0 # @@@ Change this on Server version increment
134
134
 
135
135
  def __init__(self, *,
136
136
  url=_PROD,
@@ -394,7 +394,8 @@ class SparclClient(): # was SparclApi()
394
394
  raise ex.NoCommonIdField(msg)
395
395
  outfields = [idfld]
396
396
  dataset_list = self.fields.all_drs
397
- #! self._validate_science_fields(outfields, dataset_list=dataset_list) # DLS-401
397
+ #! self._validate_science_fields(outfields,
398
+ #! dataset_list=dataset_list) # DLS-401
398
399
  dr = list(dataset_list)[0]
399
400
  if len(constraints) > 0:
400
401
  self._validate_science_fields(constraints.keys(),
@@ -475,6 +476,56 @@ class SparclClient(): # was SparclApi()
475
476
  return ret
476
477
  # END missing()
477
478
 
479
+ def missing_specids(self, specid_list, *, dataset_list=None,
480
+ countOnly=False, verbose=False):
481
+ """Return the subset of specids in the given specid_list that are
482
+ NOT stored in the SPARC database.
483
+
484
+ Args:
485
+ specid_list (:obj:`list`): List of specids.
486
+
487
+ dataset_list (:obj:`list`, optional): List of data sets from
488
+ which to find missing specids. Defaults to None, meaning
489
+ all data sets hosted on the SPARC database.
490
+
491
+ countOnly (:obj:`bool`, optional): Set to True to return only
492
+ a count of the missing specids from the specid_list.
493
+ Defaults to False.
494
+
495
+ verbose (:obj:`bool`, optional): Set to True for in-depth return
496
+ statement. Defaults to False.
497
+
498
+ Returns:
499
+ A list of the subset of specids in the given specid_list that
500
+ are NOT stored in the SPARC database.
501
+
502
+ Example:
503
+ >>> client = SparclClient(url=_PAT)
504
+ >>> specids = ['7972592460248666112', '3663710814482833408']
505
+ >>> client.missing_specids(specids + ['bad_id'])
506
+ ['bad_id']
507
+ """
508
+ if dataset_list is None:
509
+ dataset_list = self.fields.all_drs
510
+ assert isinstance(dataset_list, (list, set)), (
511
+ f'DATASET_LIST must be a list. Found {dataset_list}')
512
+
513
+ verbose = verbose or self.verbose
514
+ uparams = dict(dataset_list=','.join(dataset_list))
515
+ qstr = urlencode(uparams)
516
+ url = f'{self.apiurl}/missing_specids/?{qstr}'
517
+ specids = list(specid_list)
518
+ if verbose:
519
+ print(f'Using url="{url}"')
520
+ res = requests.post(url, json=specids, timeout=self.timeout)
521
+
522
+ res.raise_for_status()
523
+ if res.status_code != 200:
524
+ raise Exception(res)
525
+ ret = res.json()
526
+ return ret
527
+ # END missing_specids()
528
+
478
529
  # Include fields are Science (not internal) names. But the mapping
479
530
  # of Internal to Science name depends on DataSet. Its possible
480
531
  # for a field (Science name) to be valid in one DataSet but not
@@ -667,6 +718,7 @@ class SparclClient(): # was SparclApi()
667
718
  format='pkl', # 'json',
668
719
  include='DEFAULT',
669
720
  dataset_list=None,
721
+ limit=500,
670
722
  verbose=False):
671
723
  """Retrieve spectra records from the SPARC database by list of specids.
672
724
 
@@ -716,7 +768,7 @@ class SparclClient(): # was SparclApi()
716
768
  dr = list(self.fields.all_drs)[0]
717
769
  idfld = self.fields._science_name('id', dr)
718
770
 
719
- found = self.find([idfld], constraints=constraints)
771
+ found = self.find([idfld], constraints=constraints, limit=limit)
720
772
  if verbose:
721
773
  print(f'Found {found.count} matches.')
722
774
  res = self.retrieve(found.ids,
@@ -724,6 +776,7 @@ class SparclClient(): # was SparclApi()
724
776
  format=format,
725
777
  include=include,
726
778
  dataset_list=dataset_list,
779
+ limit=limit,
727
780
  verbose=verbose)
728
781
  if verbose:
729
782
  print(f'Got {res.count} records.')
sparcl/gather_2d.py CHANGED
@@ -1,8 +1,6 @@
1
1
  """Align or resample spectra related fields across multiple records."""
2
2
  # See client.py for Doctest example
3
3
  #
4
- # See:
5
- # https://spectres.readthedocs.io/en/latest/
6
4
  # For info about problems with floating point,
7
5
  # See: https://docs.python.org/3/tutorial/floatingpoint.html
8
6
  # Also: https://docs.python.org/3/library/decimal.html#floating-point-notes
@@ -10,41 +8,11 @@
10
8
  import math
11
9
  from decimal import Decimal
12
10
  #
13
- import spectres
14
11
  import numpy as np
15
12
  #
16
13
  import sparcl.client
17
14
 
18
15
 
19
- # Per paper, should be able to pass all flux in one call to spectres
20
- # https://arxiv.org/pdf/1705.05165.pdf
21
- # Perhaps users would rather the bins uniform (1,5,20 Angstroms?)
22
- def _resample_flux(records, wavstep=1):
23
- smallest = math.floor(min([min(r.wavelength) for r in records]))
24
- largest = math.ceil(max([max(r.wavelength) for r in records]))
25
-
26
- #!wrange = largest - smallest
27
- #new_wavs = np.fromfunction(lambda i: i + smallest, (wrange,), dtype=int)
28
- #flux_2d = np.ones([len(records), wrange])
29
-
30
- new_wavs = np.array(range(smallest, largest + 1, wavstep))
31
- flux_2d = np.full([len(records), len(new_wavs)], None, dtype=float)
32
-
33
- for idx, rec in enumerate(records):
34
- flux_2d[idx] = spectres.spectres(new_wavs,
35
- rec.wavelength,
36
- rec.flux,
37
- verbose=False)
38
- return flux_2d, new_wavs
39
-
40
-
41
- def _tt0(numrecs=20):
42
- client = sparcl.client.SparclClient()
43
- found = client.find(constraints=dict(data_release=['BOSS-DR16']),
44
- limit=numrecs)
45
- got = client.retrieve(found.ids)
46
- flux_2d, new_wavs = _resample_flux(got.records)
47
- return flux_2d, new_wavs
48
16
 
49
17
 
50
18
  # Map every wavelength of every record to index (ri,wi)
@@ -88,14 +56,17 @@ def _validate_wavelength_alignment(records, window, offsets, precision=None):
88
56
  else:
89
57
  recwl = Decimal(rwl).quantize(PLACES)
90
58
  wwl = window[offsets[ri] + wi]
91
- msg = (f'Wavelength in '
92
- f'Record[{ri}][{wi}] ({recwl}) does not match '
93
- f'Window[{offsets[ri]+wi} = offset[{ri}]={offsets[ri]} '
94
- f'+ {wi}] ({wwl})'
95
- )
96
- assert recwl == wwl, msg
97
- # f'RecWL[{wi}] {rwl} != WindowWL[{offsets[ri+wi]}] {wwl} '
98
- # f'offset={offsets[ri]}')
59
+ #! msg = (f'Wavelength in '
60
+ #! f'Record[{ri}][{wi}] ({recwl}) does not match '
61
+ #! f'Window[{offsets[ri]+wi} = offset[{ri}]={offsets[ri]} '
62
+ #! f'+ {wi}] ({wwl})'
63
+ #! )
64
+ #! assert recwl == wwl, msg
65
+ if recwl != wwl:
66
+ msg = (f'The spectra cannot be aligned with the given'
67
+ f' "precision" parameter ({precision}).'
68
+ f' Try lowering the precision value.')
69
+ raise Exception(msg)
99
70
 
100
71
 
101
72
  # We want to align a bunch of records by wavelength into a single
@@ -127,6 +98,7 @@ def _tt1(numrecs=20, dr='BOSS-DR16'):
127
98
 
128
99
 
129
100
  # precision:: number of decimal places
101
+ # "records" must contain "wavelength" field.
130
102
  def _wavelength_grid_offsets(records, precision=11):
131
103
  PLACES = Decimal(10) ** -precision
132
104
 
@@ -175,9 +147,14 @@ def _field_grid(records, fieldName, grid, offsets, precision=None):
175
147
  #! ar = _flux_grid(records, grid, offsets, precision=precision)
176
148
  #! return ar, np.array([float(x) for x in grid])
177
149
 
150
+ def _validate_spectra_fields(records, fields):
151
+ spectra_fields = [client.fields.n2o['BOSS-DR16'][k] for k,v in client.fields.attrs['BOSS-DR16'].items() if v['storage']=='S']
152
+ [k for k in records[0].keys() if not k.startswith('_')]
153
+
154
+
178
155
  # TOP level: Intended for access from Jupyter NOTEBOOK.
179
156
  # Align spectra related field from records into one array using quantization.
180
- def align_records(records, fields=None, precision=7):
157
+ def align_records(records, fields=['flux','wavelength'], precision=7):
181
158
  """Align given spectra-type fields to a common wavelength grid.
182
159
 
183
160
  Args:
@@ -186,9 +163,11 @@ def align_records(records, fields=None, precision=7):
186
163
 
187
164
  fields (:obj:`list`, optional): List of Science Field Names of
188
165
  spectra related fields to align and include in the results.
166
+ DEFAULT=['flux', 'wavelength']
189
167
 
190
168
  precision (:obj:`int`, optional): Number of decimal points to use for
191
- quantizing wavelengths into a grid. Default=7
169
+ quantizing wavelengths into a grid.
170
+ DEFAULT=7
192
171
 
193
172
  Returns:
194
173
  tuple containing:
@@ -198,7 +177,7 @@ def align_records(records, fields=None, precision=7):
198
177
 
199
178
  Example:
200
179
  >>> client = sparcl.client.SparclClient()
201
- >>> specflds = ['wavelength', 'flux', 'ivar', 'mask', 'model']
180
+ >>> specflds = ['wavelength', 'model']
202
181
  >>> cons = {"data_release": ['BOSS-DR16']}
203
182
  >>> found = client.find(constraints=cons, limit=21)
204
183
  >>> got = client.retrieve(found.ids, include=specflds)
@@ -207,15 +186,20 @@ def align_records(records, fields=None, precision=7):
207
186
  (21, 4670)
208
187
 
209
188
  """
189
+ # Report Garbage In
190
+ if 'wavelength' not in fields:
191
+ msg = (f'You must provide "wavelength" in the list provided'
192
+ f' in the "fields" paramter. Got: {fields}')
193
+ raise Exception(msg)
194
+ if 'wavelength' not in records[0]:
195
+ msg = (f'Records must contain the "wavelength" field.'
196
+ f' The first record contains fields: {sorted(records[0].keys())}')
197
+ raise Exception(msg)
198
+
199
+ #! _validate_spectra_fields(records, fields)
210
200
  grid, offsets = _wavelength_grid_offsets(records, precision=precision)
211
201
  _validate_wavelength_alignment(records, grid, offsets, precision=precision)
212
202
 
213
- # One slice for each record; each slice a 2darray(wavelength, fieldName)=fldVal
214
- #! slices = list()
215
- #! for rec in records:
216
- #! ar = rec_grid(rec, fields, grid, offsets, precision=None):
217
- #! slices.append(ar)
218
-
219
203
  # One slice for each field; each slice a 2darray(wavelength, record)=fldVal
220
204
  adict = dict()
221
205
  for fld in fields:
@@ -0,0 +1,36 @@
1
+ # NOT INTENDED FOR PUBLIC USE!
2
+ #
3
+ # See:
4
+ # https://spectres.readthedocs.io/en/latest/
5
+
6
+ import spectres
7
+
8
+ # Per paper, should be able to pass all flux in one call to spectres
9
+ # https://arxiv.org/pdf/1705.05165.pdf
10
+ # Perhaps users would rather the bins uniform (1,5,20 Angstroms?)
11
+ def _resample_flux(records, wavstep=1):
12
+ smallest = math.floor(min([min(r.wavelength) for r in records]))
13
+ largest = math.ceil(max([max(r.wavelength) for r in records]))
14
+
15
+ #!wrange = largest - smallest
16
+ #new_wavs = np.fromfunction(lambda i: i + smallest, (wrange,), dtype=int)
17
+ #flux_2d = np.ones([len(records), wrange])
18
+
19
+ new_wavs = np.array(range(smallest, largest + 1, wavstep))
20
+ flux_2d = np.full([len(records), len(new_wavs)], None, dtype=float)
21
+
22
+ for idx, rec in enumerate(records):
23
+ flux_2d[idx] = spectres.spectres(new_wavs,
24
+ rec.wavelength,
25
+ rec.flux,
26
+ verbose=False)
27
+ return flux_2d, new_wavs
28
+
29
+
30
+ def _tt0(numrecs=20):
31
+ client = sparcl.client.SparclClient()
32
+ found = client.find(constraints=dict(data_release=['BOSS-DR16']),
33
+ limit=numrecs)
34
+ got = client.retrieve(found.ids)
35
+ flux_2d, new_wavs = _resample_flux(got.records)
36
+ return flux_2d, new_wavs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sparclclient
3
- Version: 1.2.0b3.dev9
3
+ Version: 1.2.0b4
4
4
  Summary: A client for getting spectra data from NOIRLab.
5
5
  Home-page: https://github.com/astro-datalab/sparclclient
6
6
  Author: NOIRLab DataLab
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Requires-Python: >=3.6
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: requests (==2.26.0)
18
+ Requires-Dist: requests (==2.31.0)
19
19
  Requires-Dist: numpy
20
20
  Requires-Dist: spectres
21
21
 
@@ -0,0 +1,20 @@
1
+ sparcl/Results.py,sha256=S4jQcXnw6qfdIEL-NEsCqMK6LolFaERGxjNWIvNhACM,8039
2
+ sparcl/__init__.py,sha256=sLkvMfJ715Hbp_Lo0vJSC0RRqDYMcvrlMXHbJBBce_M,1030
3
+ sparcl/big_retrieve.py,sha256=q0ScH87QqPL4bz4g0hB0AO3k4c_TiuQrWjBJHqHhE60,798
4
+ sparcl/client.py,sha256=2bmwXjLU28Apod7O7ohkwHAvcGRbURAolYq9xERj9HE,31749
5
+ sparcl/conf.py,sha256=O9l4-vpWBZK0QjhHxjskGO8kHPxBj7mkWlchd2rot1c,953
6
+ sparcl/dls_376.py,sha256=WvZjuZFRU0jgH3ELRrMQdslkMWiF2wFQrSag0cYii-I,887
7
+ sparcl/exceptions.py,sha256=q7ONsLsop9OQJJCD4SEzfdsojv0yo3WQT0SluaxGOQ0,3813
8
+ sparcl/fields.py,sha256=7MpaJQr2d1GktS7aeM4010jyLqDdKQ7BZIF9hM0IjII,5002
9
+ sparcl/gather_2d.py,sha256=ZRr41vNHV4tnf63-QuTu04SlWv6TOzK-CeHpbt9YwOY,9254
10
+ sparcl/resample_spectra.py,sha256=2MO-sDCCFg2eNiK6jQs2EJRu4bNnXycGV8WaOydssG4,1329
11
+ sparcl/type_conversion.py,sha256=RX7OD1iGuuUrf-yAd0ISdiqBq4CP7QlCw0vvkAdHdsQ,13112
12
+ sparcl/unsupported.py,sha256=vkSaK3Ppcxx6mMsqBktUjI0uS7RwBJYH2BkBABsnyIM,1867
13
+ sparcl/utils.py,sha256=YlLUP0j4thUyEwTJAaqJ7zzsvbCxPe5EYTn9kvWGfBY,4682
14
+ sparcl/benchmarks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ sparcl/benchmarks/benchmarks.py,sha256=FPZ2KExfVWHhGt3B4VyfgOhxxsemj7OeBWJO0dyDDC4,9667
16
+ sparclclient-1.2.0b4.dist-info/LICENSE,sha256=y10EluGMCzGs9X4oYCYyix3l6u-lawB_vlGR8qe442Q,1576
17
+ sparclclient-1.2.0b4.dist-info/METADATA,sha256=NtJ980uIF8tOtRNULNS_Y4UlPDI9Gg3ToLzj31Hnyng,867
18
+ sparclclient-1.2.0b4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
19
+ sparclclient-1.2.0b4.dist-info/top_level.txt,sha256=d5CZ3Duxq3MyQTB2ZqOrdtSBv4GdVceF-pOZFmsuHZY,7
20
+ sparclclient-1.2.0b4.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- sparcl/Results.py,sha256=yHetKpwujeqW2RXloo-_9d3JgTu11VLrwSZzVwqZcJU,8000
2
- sparcl/__init__.py,sha256=OxAYp-Ca2BNX2OhG2VesOv1QdBPa5TPbkdiaG2xp4gY,1035
3
- sparcl/big_retrieve.py,sha256=q0ScH87QqPL4bz4g0hB0AO3k4c_TiuQrWjBJHqHhE60,798
4
- sparcl/client.py,sha256=EbLkZmEnTMUh2AnijIrqIbUalAcm3LQnGM6RkBbTWUM,29684
5
- sparcl/conf.py,sha256=O9l4-vpWBZK0QjhHxjskGO8kHPxBj7mkWlchd2rot1c,953
6
- sparcl/dls_376.py,sha256=WvZjuZFRU0jgH3ELRrMQdslkMWiF2wFQrSag0cYii-I,887
7
- sparcl/exceptions.py,sha256=q7ONsLsop9OQJJCD4SEzfdsojv0yo3WQT0SluaxGOQ0,3813
8
- sparcl/fields.py,sha256=7MpaJQr2d1GktS7aeM4010jyLqDdKQ7BZIF9hM0IjII,5002
9
- sparcl/gather_2d.py,sha256=0AOBbjt8orrMg-IgOgIjTruHMFxlUqwgN5WTopab7Ao,9799
10
- sparcl/type_conversion.py,sha256=RX7OD1iGuuUrf-yAd0ISdiqBq4CP7QlCw0vvkAdHdsQ,13112
11
- sparcl/unsupported.py,sha256=vkSaK3Ppcxx6mMsqBktUjI0uS7RwBJYH2BkBABsnyIM,1867
12
- sparcl/utils.py,sha256=YlLUP0j4thUyEwTJAaqJ7zzsvbCxPe5EYTn9kvWGfBY,4682
13
- sparcl/benchmarks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- sparcl/benchmarks/benchmarks.py,sha256=FPZ2KExfVWHhGt3B4VyfgOhxxsemj7OeBWJO0dyDDC4,9667
15
- sparclclient-1.2.0b3.dev9.dist-info/LICENSE,sha256=y10EluGMCzGs9X4oYCYyix3l6u-lawB_vlGR8qe442Q,1576
16
- sparclclient-1.2.0b3.dev9.dist-info/METADATA,sha256=6vglH_6at8TrSgsV8eoWxycL0E-zjUfyCqomQ-R3nhA,872
17
- sparclclient-1.2.0b3.dev9.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
18
- sparclclient-1.2.0b3.dev9.dist-info/top_level.txt,sha256=d5CZ3Duxq3MyQTB2ZqOrdtSBv4GdVceF-pOZFmsuHZY,7
19
- sparclclient-1.2.0b3.dev9.dist-info/RECORD,,