arvi 0.1.10__py3-none-any.whl → 0.1.11__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.
Potentially problematic release.
This version of arvi might be problematic. Click here for more details.
- arvi/config.py +1 -0
- arvi/dace_wrapper.py +60 -49
- arvi/extra_data.py +11 -2
- arvi/plots.py +107 -27
- arvi/simbad_wrapper.py +15 -0
- arvi/stats.py +16 -2
- arvi/timeseries.py +74 -29
- arvi/utils.py +14 -0
- {arvi-0.1.10.dist-info → arvi-0.1.11.dist-info}/METADATA +1 -1
- {arvi-0.1.10.dist-info → arvi-0.1.11.dist-info}/RECORD +13 -13
- {arvi-0.1.10.dist-info → arvi-0.1.11.dist-info}/LICENSE +0 -0
- {arvi-0.1.10.dist-info → arvi-0.1.11.dist-info}/WHEEL +0 -0
- {arvi-0.1.10.dist-info → arvi-0.1.11.dist-info}/top_level.txt +0 -0
arvi/config.py
CHANGED
arvi/dace_wrapper.py
CHANGED
|
@@ -5,7 +5,7 @@ import numpy as np
|
|
|
5
5
|
from dace_query import DaceClass
|
|
6
6
|
from dace_query.spectroscopy import SpectroscopyClass, Spectroscopy as default_Spectroscopy
|
|
7
7
|
from .setup_logger import logger
|
|
8
|
-
from .utils import create_directory, all_logging_disabled, stdout_disabled
|
|
8
|
+
from .utils import create_directory, all_logging_disabled, stdout_disabled, tqdm
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def load_spectroscopy() -> SpectroscopyClass:
|
|
@@ -156,6 +156,13 @@ def check_existing(output_directory, files, type):
|
|
|
156
156
|
f.partition('.fits')[0] for f in os.listdir(output_directory)
|
|
157
157
|
if type in f
|
|
158
158
|
]
|
|
159
|
+
|
|
160
|
+
# also check for lowercase type
|
|
161
|
+
existing += [
|
|
162
|
+
f.partition('.fits')[0] for f in os.listdir(output_directory)
|
|
163
|
+
if type.lower() in f
|
|
164
|
+
]
|
|
165
|
+
|
|
159
166
|
if os.name == 'nt': # on Windows, be careful with ':' in filename
|
|
160
167
|
import re
|
|
161
168
|
existing = [re.sub(r'T(\d+)_(\d+)_(\d+)', r'T\1:\2:\3', f) for f in existing]
|
|
@@ -175,7 +182,7 @@ def download(files, type, output_directory):
|
|
|
175
182
|
""" Download files from DACE """
|
|
176
183
|
Spectroscopy = load_spectroscopy()
|
|
177
184
|
# with stdout_disabled(), all_logging_disabled():
|
|
178
|
-
Spectroscopy.download_files(files, file_type=type,
|
|
185
|
+
Spectroscopy.download_files(files, file_type=type.lower(),
|
|
179
186
|
output_directory=output_directory)
|
|
180
187
|
|
|
181
188
|
def extract_fits(output_directory):
|
|
@@ -194,15 +201,16 @@ def extract_fits(output_directory):
|
|
|
194
201
|
return files
|
|
195
202
|
|
|
196
203
|
|
|
197
|
-
def
|
|
198
|
-
|
|
204
|
+
def do_download_filetype(type, raw_files, output_directory, clobber=False,
|
|
205
|
+
verbose=True, chunk_size=20):
|
|
206
|
+
""" Download CCFs / S1Ds / S2Ds from DACE """
|
|
199
207
|
raw_files = np.atleast_1d(raw_files)
|
|
200
208
|
|
|
201
209
|
create_directory(output_directory)
|
|
202
210
|
|
|
203
211
|
# check existing files to avoid re-downloading
|
|
204
212
|
if not clobber:
|
|
205
|
-
raw_files = check_existing(output_directory, raw_files,
|
|
213
|
+
raw_files = check_existing(output_directory, raw_files, type)
|
|
206
214
|
|
|
207
215
|
# any file left to download?
|
|
208
216
|
if raw_files.size == 0:
|
|
@@ -212,68 +220,71 @@ def do_download_ccf(raw_files, output_directory, clobber=False, verbose=True):
|
|
|
212
220
|
|
|
213
221
|
if verbose:
|
|
214
222
|
n = raw_files.size
|
|
215
|
-
logger.info(f"Downloading {n}
|
|
223
|
+
logger.info(f"Downloading {n} {type}s into '{output_directory}'...")
|
|
216
224
|
|
|
217
|
-
|
|
225
|
+
# avoid an empty chunk
|
|
226
|
+
if chunk_size > n:
|
|
227
|
+
chunk_size = n
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
|
|
229
|
+
for files in tqdm(zip(*(iter(raw_files),) * chunk_size), total=n // chunk_size):
|
|
230
|
+
download(files, type, output_directory)
|
|
231
|
+
extract_fits(output_directory)
|
|
221
232
|
|
|
222
|
-
|
|
233
|
+
logger.info('Extracted .fits files')
|
|
223
234
|
|
|
224
235
|
|
|
225
|
-
def do_download_s1d(raw_files, output_directory, clobber=False, verbose=True):
|
|
226
|
-
|
|
227
|
-
|
|
236
|
+
# def do_download_s1d(raw_files, output_directory, clobber=False, verbose=True):
|
|
237
|
+
# """ Download S1Ds from DACE """
|
|
238
|
+
# raw_files = np.atleast_1d(raw_files)
|
|
228
239
|
|
|
229
|
-
|
|
240
|
+
# create_directory(output_directory)
|
|
230
241
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
242
|
+
# # check existing files to avoid re-downloading
|
|
243
|
+
# if not clobber:
|
|
244
|
+
# raw_files = check_existing(output_directory, raw_files, 'S1D')
|
|
234
245
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
# # any file left to download?
|
|
247
|
+
# if raw_files.size == 0:
|
|
248
|
+
# if verbose:
|
|
249
|
+
# logger.info('no files to download')
|
|
250
|
+
# return
|
|
240
251
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
252
|
+
# if verbose:
|
|
253
|
+
# n = raw_files.size
|
|
254
|
+
# logger.info(f"Downloading {n} S1Ds into '{output_directory}'...")
|
|
244
255
|
|
|
245
|
-
|
|
256
|
+
# download(raw_files, 's1d', output_directory)
|
|
246
257
|
|
|
247
|
-
|
|
248
|
-
|
|
258
|
+
# if verbose:
|
|
259
|
+
# logger.info('Extracting .fits files')
|
|
249
260
|
|
|
250
|
-
|
|
261
|
+
# extract_fits(output_directory)
|
|
251
262
|
|
|
252
263
|
|
|
253
|
-
def do_download_s2d(raw_files, output_directory, clobber=False, verbose=True):
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
# def do_download_s2d(raw_files, output_directory, clobber=False, verbose=True):
|
|
265
|
+
# """ Download S2Ds from DACE """
|
|
266
|
+
# raw_files = np.atleast_1d(raw_files)
|
|
256
267
|
|
|
257
|
-
|
|
268
|
+
# create_directory(output_directory)
|
|
258
269
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
270
|
+
# # check existing files to avoid re-downloading
|
|
271
|
+
# if not clobber:
|
|
272
|
+
# raw_files = check_existing(output_directory, raw_files, 'S2D')
|
|
262
273
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
274
|
+
# # any file left to download?
|
|
275
|
+
# if raw_files.size == 0:
|
|
276
|
+
# if verbose:
|
|
277
|
+
# logger.info('no files to download')
|
|
278
|
+
# return
|
|
268
279
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
# if verbose:
|
|
281
|
+
# n = raw_files.size
|
|
282
|
+
# logger.info(f"Downloading {n} S2Ds into '{output_directory}'...")
|
|
272
283
|
|
|
273
|
-
|
|
284
|
+
# download(raw_files, 's2d', output_directory)
|
|
274
285
|
|
|
275
|
-
|
|
276
|
-
|
|
286
|
+
# if verbose:
|
|
287
|
+
# logger.info('Extracting .fits files')
|
|
277
288
|
|
|
278
|
-
|
|
279
|
-
|
|
289
|
+
# extracted_files = extract_fits(output_directory)
|
|
290
|
+
# return extracted_files
|
arvi/extra_data.py
CHANGED
|
@@ -19,15 +19,24 @@ def get_extra_data(star, instrument=None, path=None, verbose=True):
|
|
|
19
19
|
# print(metadata)
|
|
20
20
|
|
|
21
21
|
files = glob(os.path.join(path, star + '*'))
|
|
22
|
+
files = [f for f in files if os.path.isfile(f)]
|
|
23
|
+
files = [f for f in files if not os.path.basename(f).endswith('.zip')]
|
|
24
|
+
|
|
22
25
|
if len(files) == 0:
|
|
23
26
|
raise FileNotFoundError
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
def get_instruments(files):
|
|
29
|
+
instruments = [os.path.basename(f).split('.')[0] for f in files]
|
|
30
|
+
instruments = [i.split('_', maxsplit=1)[1] for i in instruments]
|
|
31
|
+
return instruments
|
|
32
|
+
|
|
33
|
+
instruments = get_instruments(files)
|
|
27
34
|
|
|
28
35
|
if instrument is not None:
|
|
29
36
|
if not any([instrument in i for i in instruments]):
|
|
30
37
|
raise FileNotFoundError
|
|
38
|
+
files = [f for f in files if instrument in f]
|
|
39
|
+
instruments = get_instruments(files)
|
|
31
40
|
|
|
32
41
|
if verbose:
|
|
33
42
|
logger.info(f'loading extra data for {star}')
|
arvi/plots.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from functools import partial, partialmethod
|
|
3
|
+
from itertools import cycle
|
|
3
4
|
|
|
5
|
+
import matplotlib.collections
|
|
4
6
|
import numpy as np
|
|
5
7
|
import matplotlib
|
|
6
8
|
import matplotlib.pyplot as plt
|
|
@@ -15,7 +17,7 @@ from . import config
|
|
|
15
17
|
|
|
16
18
|
def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
17
19
|
remove_50000=False, tooltips=False, label=None, N_in_label=False,
|
|
18
|
-
versus_n=False, show_histogram=False, **kwargs):
|
|
20
|
+
versus_n=False, show_histogram=False, bw=False, **kwargs):
|
|
19
21
|
""" Plot the RVs
|
|
20
22
|
|
|
21
23
|
Args:
|
|
@@ -38,6 +40,8 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
38
40
|
show_histogram (bool, optional)
|
|
39
41
|
Whether to show a panel with the RV histograms (per intrument).
|
|
40
42
|
Defaults to False.
|
|
43
|
+
bw (bool, optional):
|
|
44
|
+
Adapt plot to black and white. Defaults to False.
|
|
41
45
|
|
|
42
46
|
Returns:
|
|
43
47
|
Figure: the figure
|
|
@@ -58,7 +62,7 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
58
62
|
ax, axh = ax
|
|
59
63
|
fig = ax.figure
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
|
|
62
66
|
kwargs.setdefault('ls', '')
|
|
63
67
|
kwargs.setdefault('capsize', 0)
|
|
64
68
|
kwargs.setdefault('ms', 4)
|
|
@@ -66,10 +70,22 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
66
70
|
if remove_50000:
|
|
67
71
|
time_offset = 50000
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
strict = kwargs.pop('strict', False)
|
|
74
|
+
instruments = self._check_instrument(instrument, strict=strict)
|
|
75
|
+
|
|
76
|
+
if bw:
|
|
77
|
+
markers = cycle(('o', 'P', 's', '^', '*'))
|
|
78
|
+
else:
|
|
79
|
+
markers = cycle(('o',) * len(instruments))
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
zorders = cycle(-np.argsort([getattr(self, i).error for i in instruments])[::-1])
|
|
83
|
+
except AttributeError:
|
|
84
|
+
zorders = cycle([1] * len(instruments))
|
|
70
85
|
|
|
71
86
|
cursors = {}
|
|
72
|
-
|
|
87
|
+
containers = {}
|
|
88
|
+
for _i, inst in enumerate(instruments):
|
|
73
89
|
s = self if self._child else getattr(self, inst)
|
|
74
90
|
if s.mask.sum() == 0:
|
|
75
91
|
continue
|
|
@@ -81,37 +97,42 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
81
97
|
p = p.replace('_', '.')
|
|
82
98
|
_label = f'{i}-{p}'
|
|
83
99
|
else:
|
|
84
|
-
|
|
100
|
+
if isinstance(label, list):
|
|
101
|
+
_label = label[_i]
|
|
102
|
+
else:
|
|
103
|
+
_label = label
|
|
85
104
|
|
|
86
105
|
if versus_n:
|
|
87
|
-
container = ax.errorbar(np.arange(1, s.mtime.size + 1),
|
|
88
|
-
|
|
106
|
+
container = ax.errorbar(np.arange(1, s.mtime.size + 1), s.mvrad, s.msvrad,
|
|
107
|
+
label=_label, picker=True, marker=next(markers), zorder=next(zorders),
|
|
108
|
+
**kwargs)
|
|
89
109
|
else:
|
|
90
|
-
container = ax.errorbar(s.mtime - time_offset,
|
|
91
|
-
|
|
110
|
+
container = ax.errorbar(s.mtime - time_offset, s.mvrad, s.msvrad,
|
|
111
|
+
label=_label, picker=True, marker=next(markers), zorder=next(zorders),
|
|
112
|
+
**kwargs)
|
|
113
|
+
|
|
114
|
+
containers[inst] = list(container)
|
|
92
115
|
|
|
93
116
|
if show_histogram:
|
|
94
117
|
kw = dict(histtype='step', bins='doane', orientation='horizontal')
|
|
95
118
|
hlabel = f'{s.mvrad.std():.2f} {self.units}'
|
|
96
119
|
axh.hist(s.mvrad, **kw, label=hlabel)
|
|
97
120
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
sel.
|
|
107
|
-
text
|
|
108
|
-
|
|
109
|
-
text +=
|
|
110
|
-
#
|
|
111
|
-
# text += '
|
|
112
|
-
#
|
|
113
|
-
# text += f'mask: {_s.ccf_mask[sel.index]}'
|
|
114
|
-
sel.annotation.set_text(text)
|
|
121
|
+
# cursors[inst] = crsr = mplcursors.cursor(container, multiple=False)
|
|
122
|
+
# @crsr.connect("add")
|
|
123
|
+
# def _(sel):
|
|
124
|
+
# inst = sel.artist.get_label()
|
|
125
|
+
# _s = getattr(self, inst)
|
|
126
|
+
# vrad, svrad = _s.vrad[sel.index], _s.svrad[sel.index]
|
|
127
|
+
# sel.annotation.get_bbox_patch().set(fc="white")
|
|
128
|
+
# text = f'{inst}\n'
|
|
129
|
+
# text += f'BJD: {sel.target[0]:9.5f}\n'
|
|
130
|
+
# text += f'RV: {vrad:.3f} ± {svrad:.3f}'
|
|
131
|
+
# # if fig.canvas.manager.toolmanager.get_tool('infotool').toggled:
|
|
132
|
+
# # text += '\n\n'
|
|
133
|
+
# # text += f'date: {_s.date_night[sel.index]}\n'
|
|
134
|
+
# # text += f'mask: {_s.ccf_mask[sel.index]}'
|
|
135
|
+
# sel.annotation.set_text(text)
|
|
115
136
|
|
|
116
137
|
if show_masked:
|
|
117
138
|
if versus_n:
|
|
@@ -147,9 +168,43 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
147
168
|
fig.canvas.draw()
|
|
148
169
|
except ValueError:
|
|
149
170
|
pass
|
|
150
|
-
|
|
151
171
|
plt.connect('pick_event', on_pick_legend)
|
|
152
172
|
|
|
173
|
+
if tooltips:
|
|
174
|
+
annotations = []
|
|
175
|
+
def on_pick_point(event):
|
|
176
|
+
print('annotations:', annotations)
|
|
177
|
+
for text in annotations:
|
|
178
|
+
text.remove()
|
|
179
|
+
annotations.remove(text)
|
|
180
|
+
|
|
181
|
+
artist = event.artist
|
|
182
|
+
if isinstance(artist, (matplotlib.lines.Line2D, matplotlib.collections.LineCollection)):
|
|
183
|
+
print(event.ind, artist)
|
|
184
|
+
if isinstance(artist, matplotlib.lines.Line2D):
|
|
185
|
+
matching_instrument = [k for k, v in containers.items() if artist in v]
|
|
186
|
+
print(matching_instrument)
|
|
187
|
+
if len(matching_instrument) == 0:
|
|
188
|
+
return
|
|
189
|
+
inst = matching_instrument[0]
|
|
190
|
+
_s = getattr(self, inst)
|
|
191
|
+
ind = event.ind[0]
|
|
192
|
+
# print(_s.mtime[ind], _s.mvrad[ind], _s.msvrad[ind])
|
|
193
|
+
|
|
194
|
+
text = f'{inst}\n'
|
|
195
|
+
text += f'{_s.mtime[ind]:9.5f}\n'
|
|
196
|
+
text += f'RV: {_s.mvrad[ind]:.1f} ± {_s.msvrad[ind]:.1f}'
|
|
197
|
+
|
|
198
|
+
annotations.append(
|
|
199
|
+
ax.annotate(text, (_s.mtime[ind], _s.mvrad[ind]), xycoords='data',
|
|
200
|
+
xytext=(5, 10), textcoords='offset points', fontsize=9,
|
|
201
|
+
bbox={'boxstyle': 'round', 'fc': 'w'}, arrowprops=dict(arrowstyle="-"))
|
|
202
|
+
)
|
|
203
|
+
# ax.annotate(f'{inst}', (0.5, 0.5), xycoords=artist, ha='center', va='center')
|
|
204
|
+
fig.canvas.draw()
|
|
205
|
+
# print(event.ind, artist.get_label())
|
|
206
|
+
plt.connect('pick_event', on_pick_point)
|
|
207
|
+
|
|
153
208
|
|
|
154
209
|
if show_histogram:
|
|
155
210
|
axh.legend()
|
|
@@ -340,6 +395,31 @@ def gls(self, ax=None, label=None, fap=True, picker=True, instrument=None, **kwa
|
|
|
340
395
|
if label is not None:
|
|
341
396
|
ax.legend()
|
|
342
397
|
|
|
398
|
+
if ax.get_legend() is not None:
|
|
399
|
+
leg = ax.get_legend()
|
|
400
|
+
for text in leg.get_texts():
|
|
401
|
+
text.set_picker(True)
|
|
402
|
+
|
|
403
|
+
def on_pick_legend(event):
|
|
404
|
+
handles, labels = ax.get_legend_handles_labels()
|
|
405
|
+
artist = event.artist
|
|
406
|
+
if isinstance(artist, matplotlib.text.Text):
|
|
407
|
+
# print('handles:', handles)
|
|
408
|
+
# print('labels:', labels)
|
|
409
|
+
# print(artist.get_text())
|
|
410
|
+
try:
|
|
411
|
+
h = handles[labels.index(artist.get_text())]
|
|
412
|
+
alpha_text = {None:0.2, 1.0: 0.2, 0.2:1.0}[artist.get_alpha()]
|
|
413
|
+
alpha_point = {None: 0.0, 1.0: 0.0, 0.2: 1.0}[artist.get_alpha()]
|
|
414
|
+
h.set_alpha(alpha_point)
|
|
415
|
+
artist.set_alpha(alpha_text)
|
|
416
|
+
fig.canvas.draw()
|
|
417
|
+
except ValueError:
|
|
418
|
+
pass
|
|
419
|
+
|
|
420
|
+
if 'pick_event' not in fig.canvas.callbacks.callbacks:
|
|
421
|
+
plt.connect('pick_event', on_pick_legend)
|
|
422
|
+
|
|
343
423
|
|
|
344
424
|
if config.return_self:
|
|
345
425
|
return self
|
arvi/simbad_wrapper.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from dataclasses import dataclass, field
|
|
2
3
|
import requests
|
|
3
4
|
|
|
4
5
|
from astropy.coordinates import SkyCoord
|
|
5
6
|
import pysweetcat
|
|
6
7
|
|
|
8
|
+
DATA_PATH = os.path.dirname(__file__)
|
|
9
|
+
DATA_PATH = os.path.join(DATA_PATH, 'data')
|
|
7
10
|
|
|
8
11
|
QUERY = """
|
|
9
12
|
SELECT basic.OID,
|
|
@@ -45,6 +48,8 @@ def run_query(query):
|
|
|
45
48
|
response = requests.post(url, data=data, timeout=10)
|
|
46
49
|
except requests.ReadTimeout as err:
|
|
47
50
|
raise IndexError(err)
|
|
51
|
+
except requests.ConnectionError as err:
|
|
52
|
+
raise IndexError(err)
|
|
48
53
|
return response.content.decode()
|
|
49
54
|
|
|
50
55
|
def parse_table(table, cols=None, values=None):
|
|
@@ -94,6 +99,16 @@ class simbad:
|
|
|
94
99
|
"""
|
|
95
100
|
self.star = star
|
|
96
101
|
|
|
102
|
+
if 'kobe' in self.star.lower():
|
|
103
|
+
fname = os.path.join(DATA_PATH, 'KOBE-translate.csv')
|
|
104
|
+
kobe_translate = {}
|
|
105
|
+
if os.path.exists(fname):
|
|
106
|
+
with open(fname) as f:
|
|
107
|
+
for line in f.readlines():
|
|
108
|
+
kobe_id, catname = line.strip().split(',')
|
|
109
|
+
kobe_translate[kobe_id] = catname
|
|
110
|
+
self.star = star = kobe_translate[self.star]
|
|
111
|
+
|
|
97
112
|
# oid = run_query(query=OID_QUERY.format(star=star))
|
|
98
113
|
# self.oid = str(oid.split()[-1])
|
|
99
114
|
|
arvi/stats.py
CHANGED
|
@@ -19,15 +19,19 @@ def wmean(a, e):
|
|
|
19
19
|
raise ValueError
|
|
20
20
|
return np.average(a, weights=1 / e**2)
|
|
21
21
|
|
|
22
|
-
def rms(a):
|
|
22
|
+
def rms(a, ignore_nans=False):
|
|
23
23
|
""" Root mean square of array `a`
|
|
24
24
|
|
|
25
25
|
Args:
|
|
26
26
|
a (array): Array containing data
|
|
27
27
|
"""
|
|
28
|
+
if ignore_nans:
|
|
29
|
+
a = a[~np.isnan(a)]
|
|
30
|
+
if len(a) == 0:
|
|
31
|
+
return np.nan
|
|
28
32
|
return np.sqrt((a**2).mean())
|
|
29
33
|
|
|
30
|
-
def wrms(a, e):
|
|
34
|
+
def wrms(a, e, ignore_nans=False):
|
|
31
35
|
""" Weighted root mean square of array `a`, with uncertanty given by `e`.
|
|
32
36
|
The weighted rms is calculated using the weighted mean, where the weights
|
|
33
37
|
are equal to 1/e**2.
|
|
@@ -36,6 +40,16 @@ def wrms(a, e):
|
|
|
36
40
|
a (array): Array containing data
|
|
37
41
|
e (array): Uncertainties on `a`
|
|
38
42
|
"""
|
|
43
|
+
if ignore_nans:
|
|
44
|
+
nans = np.logical_or(np.isnan(a), np.isnan(e))
|
|
45
|
+
a = a[~nans]
|
|
46
|
+
e = e[~nans]
|
|
47
|
+
if (e == 0).any():
|
|
48
|
+
raise ZeroDivisionError('uncertainty cannot be zero')
|
|
49
|
+
if (e < 0).any():
|
|
50
|
+
raise ValueError('uncertainty cannot be negative')
|
|
51
|
+
if (a.shape != e.shape):
|
|
52
|
+
raise ValueError('arrays must have the same shape')
|
|
39
53
|
w = 1 / e**2
|
|
40
54
|
return np.sqrt(np.sum(w * (a - np.average(a, weights=w))**2) / sum(w))
|
|
41
55
|
|
arvi/timeseries.py
CHANGED
|
@@ -11,16 +11,15 @@ import numpy as np
|
|
|
11
11
|
from astropy import units
|
|
12
12
|
|
|
13
13
|
from .setup_logger import logger
|
|
14
|
-
from .config import return_self
|
|
14
|
+
from .config import return_self, check_internet
|
|
15
15
|
from .translations import translate
|
|
16
|
-
from .dace_wrapper import get_observations, get_arrays
|
|
17
|
-
from .dace_wrapper import do_download_ccf, do_download_s1d, do_download_s2d
|
|
16
|
+
from .dace_wrapper import do_download_filetype, get_observations, get_arrays
|
|
18
17
|
from .simbad_wrapper import simbad
|
|
19
18
|
from .extra_data import get_extra_data
|
|
20
19
|
from .stats import wmean, wrms
|
|
21
20
|
from .binning import bin_ccf_mask, binRV
|
|
22
21
|
from .HZ import getHZ_period
|
|
23
|
-
from .utils import strtobool
|
|
22
|
+
from .utils import strtobool, there_is_internet
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
@dataclass
|
|
@@ -71,6 +70,8 @@ class RV:
|
|
|
71
70
|
self.__star__ = translate(self.star)
|
|
72
71
|
|
|
73
72
|
if not self._child:
|
|
73
|
+
if check_internet and not there_is_internet():
|
|
74
|
+
raise ConnectionError('There is no internet connection?')
|
|
74
75
|
# complicated way to query Simbad with self.__star__ or, if that
|
|
75
76
|
# fails, try after removing a trailing 'A'
|
|
76
77
|
for target in (self.__star__, self.__star__.replace('A', '')):
|
|
@@ -226,6 +227,8 @@ class RV:
|
|
|
226
227
|
@property
|
|
227
228
|
def N_nights(self) -> int:
|
|
228
229
|
""" Number of individual nights """
|
|
230
|
+
if self.mtime.size == 0:
|
|
231
|
+
return 0
|
|
229
232
|
return binRV(self.mtime, None, None, binning_bins=True).size - 1
|
|
230
233
|
|
|
231
234
|
@property
|
|
@@ -402,7 +405,7 @@ class RV:
|
|
|
402
405
|
files = [files]
|
|
403
406
|
|
|
404
407
|
if star is None:
|
|
405
|
-
star_ = np.unique([os.path.splitext(f)[0].split('_')[0] for f in files])
|
|
408
|
+
star_ = np.unique([os.path.splitext(os.path.basename(f))[0].split('_')[0] for f in files])
|
|
406
409
|
if star_.size == 1:
|
|
407
410
|
logger.info(f'assuming star is {star_[0]}')
|
|
408
411
|
star = star_[0]
|
|
@@ -439,12 +442,12 @@ class RV:
|
|
|
439
442
|
names = header.split()
|
|
440
443
|
|
|
441
444
|
if len(names) > 3:
|
|
442
|
-
kw = dict(skip_header=
|
|
443
|
-
|
|
444
|
-
data = np.genfromtxt(f, **kw)
|
|
445
|
-
except ValueError:
|
|
445
|
+
kw = dict(skip_header=0, comments='--', names=True, dtype=None, encoding=None)
|
|
446
|
+
if '\t' in header:
|
|
446
447
|
data = np.genfromtxt(f, **kw, delimiter='\t')
|
|
447
|
-
|
|
448
|
+
else:
|
|
449
|
+
data = np.genfromtxt(f, **kw)
|
|
450
|
+
# data.dtype.names = names
|
|
448
451
|
else:
|
|
449
452
|
data = np.array([], dtype=np.dtype([]))
|
|
450
453
|
|
|
@@ -463,8 +466,10 @@ class RV:
|
|
|
463
466
|
|
|
464
467
|
if 'rhk' in data.dtype.fields:
|
|
465
468
|
_s.rhk = data['rhk']
|
|
466
|
-
|
|
467
|
-
|
|
469
|
+
_s.rhk_err = np.full_like(time, np.nan)
|
|
470
|
+
for possible_name in ['srhk', 'rhk_err']:
|
|
471
|
+
if possible_name in data.dtype.fields:
|
|
472
|
+
_s.rhk_err = data[possible_name]
|
|
468
473
|
else:
|
|
469
474
|
_s.rhk = np.zeros_like(time)
|
|
470
475
|
_s.rhk_err = np.full_like(time, np.nan)
|
|
@@ -624,11 +629,12 @@ class RV:
|
|
|
624
629
|
setattr(self, q, arr)
|
|
625
630
|
|
|
626
631
|
|
|
627
|
-
def download_ccf(self, instrument=None, limit=None, directory=None):
|
|
632
|
+
def download_ccf(self, instrument=None, index=None, limit=None, directory=None, **kwargs):
|
|
628
633
|
""" Download CCFs from DACE
|
|
629
634
|
|
|
630
635
|
Args:
|
|
631
636
|
instrument (str): Specific instrument for which to download data
|
|
637
|
+
index (int): Specific index of point for which to download data (0-based)
|
|
632
638
|
limit (int): Maximum number of files to download.
|
|
633
639
|
directory (str): Directory where to store data.
|
|
634
640
|
"""
|
|
@@ -638,18 +644,27 @@ class RV:
|
|
|
638
644
|
if instrument is None:
|
|
639
645
|
files = [file for file in self.raw_file if file.endswith('.fits')]
|
|
640
646
|
else:
|
|
641
|
-
|
|
647
|
+
strict = kwargs.pop('strict', False)
|
|
648
|
+
instrument = self._check_instrument(instrument, strict=strict)
|
|
642
649
|
files = []
|
|
643
650
|
for inst in instrument:
|
|
644
651
|
files += list(getattr(self, inst).raw_file)
|
|
645
652
|
|
|
646
|
-
|
|
653
|
+
if index is not None:
|
|
654
|
+
index = np.atleast_1d(index)
|
|
655
|
+
files = list(np.array(files)[index])
|
|
656
|
+
|
|
657
|
+
# remove empty strings
|
|
658
|
+
files = list(filter(None, files))
|
|
659
|
+
|
|
660
|
+
do_download_filetype('CCF', files[:limit], directory, **kwargs)
|
|
647
661
|
|
|
648
|
-
def download_s1d(self, instrument=None, limit=None, directory=None):
|
|
662
|
+
def download_s1d(self, instrument=None, index=None, limit=None, directory=None, **kwargs):
|
|
649
663
|
""" Download S1Ds from DACE
|
|
650
664
|
|
|
651
665
|
Args:
|
|
652
666
|
instrument (str): Specific instrument for which to download data
|
|
667
|
+
index (int): Specific index of point for which to download data (0-based)
|
|
653
668
|
limit (int): Maximum number of files to download.
|
|
654
669
|
directory (str): Directory where to store data.
|
|
655
670
|
"""
|
|
@@ -659,18 +674,27 @@ class RV:
|
|
|
659
674
|
if instrument is None:
|
|
660
675
|
files = [file for file in self.raw_file if file.endswith('.fits')]
|
|
661
676
|
else:
|
|
662
|
-
|
|
677
|
+
strict = kwargs.pop('strict', False)
|
|
678
|
+
instrument = self._check_instrument(instrument, strict=strict)
|
|
663
679
|
files = []
|
|
664
680
|
for inst in instrument:
|
|
665
681
|
files += list(getattr(self, inst).raw_file)
|
|
666
682
|
|
|
667
|
-
|
|
683
|
+
if index is not None:
|
|
684
|
+
index = np.atleast_1d(index)
|
|
685
|
+
files = list(np.array(files)[index])
|
|
668
686
|
|
|
669
|
-
|
|
687
|
+
# remove empty strings
|
|
688
|
+
files = list(filter(None, files))
|
|
689
|
+
|
|
690
|
+
do_download_filetype('S1D', files[:limit], directory, **kwargs)
|
|
691
|
+
|
|
692
|
+
def download_s2d(self, instrument=None, index=None, limit=None, directory=None, **kwargs):
|
|
670
693
|
""" Download S2Ds from DACE
|
|
671
694
|
|
|
672
695
|
Args:
|
|
673
696
|
instrument (str): Specific instrument for which to download data
|
|
697
|
+
index (int): Specific index of point for which to download data (0-based)
|
|
674
698
|
limit (int): Maximum number of files to download.
|
|
675
699
|
directory (str): Directory where to store data.
|
|
676
700
|
"""
|
|
@@ -680,12 +704,20 @@ class RV:
|
|
|
680
704
|
if instrument is None:
|
|
681
705
|
files = [file for file in self.raw_file if file.endswith('.fits')]
|
|
682
706
|
else:
|
|
683
|
-
|
|
707
|
+
strict = kwargs.pop('strict', False)
|
|
708
|
+
instrument = self._check_instrument(instrument, strict=strict)
|
|
684
709
|
files = []
|
|
685
710
|
for inst in instrument:
|
|
686
711
|
files += list(getattr(self, inst).raw_file)
|
|
687
712
|
|
|
688
|
-
|
|
713
|
+
if index is not None:
|
|
714
|
+
index = np.atleast_1d(index)
|
|
715
|
+
files = list(np.array(files)[index])
|
|
716
|
+
|
|
717
|
+
# remove empty strings
|
|
718
|
+
files = list(filter(None, files))
|
|
719
|
+
|
|
720
|
+
do_download_filetype('S2D', files[:limit], directory, **kwargs)
|
|
689
721
|
|
|
690
722
|
|
|
691
723
|
from .plots import plot, plot_fwhm, plot_bis, plot_rhk, plot_quantity
|
|
@@ -757,7 +789,9 @@ class RV:
|
|
|
757
789
|
return self
|
|
758
790
|
|
|
759
791
|
def remove_point(self, index):
|
|
760
|
-
"""
|
|
792
|
+
"""
|
|
793
|
+
Remove individual observations at a given index (or indices).
|
|
794
|
+
NOTE: Like Python, the index is 0-based.
|
|
761
795
|
|
|
762
796
|
Args:
|
|
763
797
|
index (int, list, ndarray):
|
|
@@ -1203,7 +1237,8 @@ class RV:
|
|
|
1203
1237
|
self._build_arrays()
|
|
1204
1238
|
|
|
1205
1239
|
|
|
1206
|
-
def save(self, directory=None, instrument=None, full=False,
|
|
1240
|
+
def save(self, directory=None, instrument=None, full=False,
|
|
1241
|
+
save_masked=False, save_nans=True):
|
|
1207
1242
|
""" Save the observations in .rdb files.
|
|
1208
1243
|
|
|
1209
1244
|
Args:
|
|
@@ -1238,11 +1273,18 @@ class RV:
|
|
|
1238
1273
|
continue
|
|
1239
1274
|
|
|
1240
1275
|
if full:
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1276
|
+
if save_masked:
|
|
1277
|
+
d = np.c_[
|
|
1278
|
+
_s.time, _s.vrad, _s.svrad,
|
|
1279
|
+
_s.fwhm, _s.fwhm_err,
|
|
1280
|
+
_s.rhk, _s.rhk_err,
|
|
1281
|
+
]
|
|
1282
|
+
else:
|
|
1283
|
+
d = np.c_[
|
|
1284
|
+
_s.mtime, _s.mvrad, _s.msvrad,
|
|
1285
|
+
_s.fwhm[_s.mask], _s.fwhm_err[_s.mask],
|
|
1286
|
+
_s.rhk[_s.mask], _s.rhk_err[_s.mask],
|
|
1287
|
+
]
|
|
1246
1288
|
if not save_nans:
|
|
1247
1289
|
if np.isnan(d).any():
|
|
1248
1290
|
# remove observations where any of the indicators are # NaN
|
|
@@ -1254,7 +1296,10 @@ class RV:
|
|
|
1254
1296
|
header = 'bjd\tvrad\tsvrad\tfwhm\tsfwhm\trhk\tsrhk\n'
|
|
1255
1297
|
header += '---\t----\t-----\t----\t-----\t---\t----'
|
|
1256
1298
|
else:
|
|
1257
|
-
|
|
1299
|
+
if save_masked:
|
|
1300
|
+
d = np.c_[_s.time, _s.vrad, _s.svrad]
|
|
1301
|
+
else:
|
|
1302
|
+
d = np.c_[_s.mtime, _s.mvrad, _s.msvrad]
|
|
1258
1303
|
header = 'bjd\tvrad\tsvrad\n---\t----\t-----'
|
|
1259
1304
|
|
|
1260
1305
|
file = f'{star_name}_{inst}.rdb'
|
arvi/utils.py
CHANGED
|
@@ -13,6 +13,12 @@ import logging
|
|
|
13
13
|
from glob import glob
|
|
14
14
|
import numpy as np
|
|
15
15
|
|
|
16
|
+
try:
|
|
17
|
+
from tqdm import tqdm, trange
|
|
18
|
+
except ImportError:
|
|
19
|
+
tqdm = lambda x, *args, **kwargs: x
|
|
20
|
+
trange = lambda *args, **kwargs: range(*args, **kwargs)
|
|
21
|
+
|
|
16
22
|
|
|
17
23
|
def create_directory(directory):
|
|
18
24
|
""" Create a directory if it does not exist """
|
|
@@ -70,6 +76,14 @@ def strtobool(val):
|
|
|
70
76
|
else:
|
|
71
77
|
raise ValueError("invalid truth value {!r}".format(val))
|
|
72
78
|
|
|
79
|
+
def there_is_internet(timeout=1):
|
|
80
|
+
from socket import create_connection
|
|
81
|
+
try:
|
|
82
|
+
create_connection(('8.8.8.8', 53), timeout=timeout)
|
|
83
|
+
return True
|
|
84
|
+
except OSError:
|
|
85
|
+
pass
|
|
86
|
+
return False
|
|
73
87
|
|
|
74
88
|
def find_data_file(file):
|
|
75
89
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
arvi/HZ.py,sha256=btqDFTxHeQlmvXOQKrjOpP8YFtmFjGhSZwsYYehLOaM,2885
|
|
2
2
|
arvi/__init__.py,sha256=XjBsNGlwuLftPK50u7SOmYKpmOpt9X5AIqA9LdZ8GyU,344
|
|
3
3
|
arvi/binning.py,sha256=G1nZvH2ev02quDPZCReygLkH7tX6B3hFAOoOYTfhLec,15249
|
|
4
|
-
arvi/config.py,sha256=
|
|
5
|
-
arvi/dace_wrapper.py,sha256=
|
|
6
|
-
arvi/extra_data.py,sha256=
|
|
4
|
+
arvi/config.py,sha256=XqLmIsPl9dJvco1ngANG5W868BexfuJJEaRkuKZsAK8,43
|
|
5
|
+
arvi/dace_wrapper.py,sha256=bfNzHKQUryCkZsJdEJImJY3oLIwVjflJOFQRRJ4RoAE,10125
|
|
6
|
+
arvi/extra_data.py,sha256=WEEaYeLh52Zdv0uyHO72Ys5MWS3naTAP4wJV2BJ1mbk,2551
|
|
7
7
|
arvi/instrument_specific.py,sha256=gDNu6xM0nL3AItAxipTdg3dIGaGGi7tNWE5nnad5MxM,2873
|
|
8
8
|
arvi/lbl_wrapper.py,sha256=_ViGVkpakvuBR_xhu9XJRV5EKHpj5Go6jBZGJZMIS2Y,11850
|
|
9
9
|
arvi/nasaexo_wrapper.py,sha256=xrdF4KKXmlZAqu4IQtdcqfOeUXJXoui5M-eZpnVXNlk,7311
|
|
10
|
-
arvi/plots.py,sha256=
|
|
10
|
+
arvi/plots.py,sha256=J1FR-7NgWL0zdjtD0Sumj6ZHLXSRC_EtnpXkTguxQ-s,17549
|
|
11
11
|
arvi/programs.py,sha256=OHmOW1BJUUg7xmzpTDzyAunxiGZ77QpVIN4Z9HxmE4M,3556
|
|
12
12
|
arvi/reports.py,sha256=yrdajC-zz5_kH1Ucc6cU70DK-5dpG0Xyeru-EITKpNo,3355
|
|
13
13
|
arvi/setup_logger.py,sha256=pBzaRTn0hntozjbaRVx0JIbWGuENkvYUApa6uB-FsRo,279
|
|
14
|
-
arvi/simbad_wrapper.py,sha256=
|
|
15
|
-
arvi/stats.py,sha256=
|
|
16
|
-
arvi/timeseries.py,sha256=
|
|
14
|
+
arvi/simbad_wrapper.py,sha256=F_VOHBI-KqT9q06sO2n2F1Ov6Un_1gAMP3ItBMqx-Yw,5284
|
|
15
|
+
arvi/stats.py,sha256=MQiyLvdiAFxIC29uajTy8kuxD-b2Y6mraL4AfWkRJkM,2576
|
|
16
|
+
arvi/timeseries.py,sha256=IvpjJqRL97bOwm4RpAGqvevkySj0Odjzx6vPtvlKzSI,52294
|
|
17
17
|
arvi/translations.py,sha256=eyUJei8wlsyBecTz8E_ntpP35-Mre2Tzm_mUMMGaZWY,150
|
|
18
|
-
arvi/utils.py,sha256=
|
|
18
|
+
arvi/utils.py,sha256=ay3GouZYqn66zF43KgSs8Ngsfb4YInKZEmk70YqVDoA,3676
|
|
19
19
|
arvi/data/info.svg,sha256=0IMI6W-eFoTD8acnury79WJJakpBwLa4qKS4JWpsXiI,489
|
|
20
20
|
arvi/data/obs_affected_ADC_issues.dat,sha256=pbwzvRBjS8KsLrKi1Cdgfihvo3hK3FUN8Csdysw-vAw,10653
|
|
21
21
|
arvi/data/obs_affected_blue_cryostat_issues.dat,sha256=z4AK17xfz8tGTDv1FjRvQFnio4XA6PNNfDXuicewHk4,1771
|
|
22
22
|
arvi/data/extra/HD86226_PFS1.rdb,sha256=vfAozbrKHM_j8dYkCBJsuHyD01KEM1asghe2KInwVao,3475
|
|
23
23
|
arvi/data/extra/HD86226_PFS2.rdb,sha256=F2P7dB6gVyzCglUjNheB0hIHVClC5RmARrGwbrY1cfo,4114
|
|
24
24
|
arvi/data/extra/metadata.json,sha256=C69hIw6CohyES6BI9vDWjxwSz7N4VOYX0PCgjXtYFmU,178
|
|
25
|
-
arvi-0.1.
|
|
26
|
-
arvi-0.1.
|
|
27
|
-
arvi-0.1.
|
|
28
|
-
arvi-0.1.
|
|
29
|
-
arvi-0.1.
|
|
25
|
+
arvi-0.1.11.dist-info/LICENSE,sha256=6JfQgl7SpM55t0EHMFNMnNh-AdkpGW25MwMiTnhdWQg,1068
|
|
26
|
+
arvi-0.1.11.dist-info/METADATA,sha256=cb2feqRY6mVlakZeoO86IYmPQzFLTWP8IboRNaBKVrw,1306
|
|
27
|
+
arvi-0.1.11.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
28
|
+
arvi-0.1.11.dist-info/top_level.txt,sha256=4EeiKDVLD45ztuflTGfQ3TU8GVjJg5Y95xS5XjI-utU,5
|
|
29
|
+
arvi-0.1.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|