arvi 0.1.14__tar.gz → 0.1.15__tar.gz
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-0.1.14 → arvi-0.1.15}/.github/workflows/python-publish.yml +2 -2
- {arvi-0.1.14 → arvi-0.1.15}/PKG-INFO +1 -3
- {arvi-0.1.14 → arvi-0.1.15}/arvi/binning.py +14 -9
- {arvi-0.1.14 → arvi-0.1.15}/arvi/dace_wrapper.py +1 -1
- {arvi-0.1.14 → arvi-0.1.15}/arvi/gaia_wrapper.py +1 -1
- {arvi-0.1.14 → arvi-0.1.15}/arvi/plots.py +158 -91
- {arvi-0.1.14 → arvi-0.1.15}/arvi/reports.py +4 -3
- {arvi-0.1.14 → arvi-0.1.15}/arvi/simbad_wrapper.py +3 -2
- {arvi-0.1.14 → arvi-0.1.15}/arvi/stats.py +2 -3
- {arvi-0.1.14 → arvi-0.1.15}/arvi/utils.py +13 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi.egg-info/PKG-INFO +1 -3
- {arvi-0.1.14 → arvi-0.1.15}/arvi.egg-info/requires.txt +0 -2
- {arvi-0.1.14 → arvi-0.1.15}/pyproject.toml +1 -3
- {arvi-0.1.14 → arvi-0.1.15}/.github/workflows/docs-gh-pages.yml +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/.github/workflows/install.yml +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/.gitignore +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/LICENSE +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/README.md +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/HZ.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/__init__.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/ariadne_wrapper.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/berv.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/config.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/extra/HD86226_PFS1.rdb +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/extra/HD86226_PFS2.rdb +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/extra/metadata.json +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/info.svg +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/obs_affected_ADC_issues.dat +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/data/obs_affected_blue_cryostat_issues.dat +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/extra_data.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/headers.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/instrument_specific.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/lbl_wrapper.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/nasaexo_wrapper.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/programs.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/setup_logger.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/spectra.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/stellar.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/timeseries.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi/translations.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi.egg-info/SOURCES.txt +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi.egg-info/dependency_links.txt +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/arvi.egg-info/top_level.txt +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/docs/API.md +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/docs/detailed.md +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/docs/index.md +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/docs/logo/detective.png +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/docs/logo/logo.png +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/mkdocs.yml +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/setup.cfg +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/setup.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/tests/test_binning.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/tests/test_import_object.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/tests/test_simbad.py +0 -0
- {arvi-0.1.14 → arvi-0.1.15}/tests/test_stats.py +0 -0
|
@@ -22,9 +22,9 @@ jobs:
|
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
|
|
24
24
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
26
|
- name: Set up Python
|
|
27
|
-
uses: actions/setup-python@
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
28
|
with:
|
|
29
29
|
python-version: '3.x'
|
|
30
30
|
- name: Install dependencies
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arvi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: The Automated RV Inspector
|
|
5
5
|
Author-email: João Faria <joao.faria@unige.ch>
|
|
6
6
|
License: MIT
|
|
@@ -14,11 +14,9 @@ Requires-Dist: mock; python_version < "3.3"
|
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: scipy
|
|
16
16
|
Requires-Dist: matplotlib
|
|
17
|
-
Requires-Dist: mplcursors
|
|
18
17
|
Requires-Dist: astropy
|
|
19
18
|
Requires-Dist: dace-query
|
|
20
19
|
Requires-Dist: loguru
|
|
21
|
-
Requires-Dist: mpldatacursor
|
|
22
20
|
Requires-Dist: tqdm
|
|
23
21
|
Requires-Dist: pySWEETCat
|
|
24
22
|
Requires-Dist: kepmodel
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
from numpy.testing import suppress_warnings
|
|
3
|
-
|
|
4
|
-
from scipy.stats import binned_statistic as old_binned_statistic,\
|
|
5
|
-
binned_statistic_dd as old_binned_statistic_dd
|
|
6
2
|
|
|
7
3
|
from .setup_logger import logger
|
|
8
4
|
|
|
@@ -38,6 +34,7 @@ def binned_statistic(x, values, statistic='mean', bins=10, range=None,
|
|
|
38
34
|
|
|
39
35
|
def binned_statistic_dd(sample, values, statistic='mean', bins=10, range=None,
|
|
40
36
|
expand_binnumbers=False, weights=None):
|
|
37
|
+
from numpy.testing import suppress_warnings
|
|
41
38
|
known_stats = [
|
|
42
39
|
'mean', 'median', 'count', 'sum', 'std', 'min', 'max', 'ptp'
|
|
43
40
|
]
|
|
@@ -214,11 +211,13 @@ def binned_statistic_dd(sample, values, statistic='mean', bins=10, range=None,
|
|
|
214
211
|
return result, edges, binnumbers
|
|
215
212
|
|
|
216
213
|
|
|
217
|
-
# put back the documentation
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
214
|
+
# # put back the documentation
|
|
215
|
+
# from scipy.stats import binned_statistic as old_binned_statistic,\
|
|
216
|
+
# binned_statistic_dd as old_binned_statistic_dd
|
|
217
|
+
# doc1 = old_binned_statistic.__doc__
|
|
218
|
+
# doc2 = old_binned_statistic_dd.__doc__
|
|
219
|
+
# binned_statistic.__doc__ = doc1
|
|
220
|
+
# binned_statistic_dd.__doc__ = doc2
|
|
222
221
|
|
|
223
222
|
###############################################################################
|
|
224
223
|
|
|
@@ -339,6 +338,9 @@ def binRV(time, rv, err=None, stat='wmean', tstat='wmean', estat='addquad',
|
|
|
339
338
|
if (err is not None) and (stat == 'wmean'):
|
|
340
339
|
stat = wmean # default is weighted mean
|
|
341
340
|
|
|
341
|
+
if (err is None) and (stat == 'wmean'):
|
|
342
|
+
stat = 'mean'
|
|
343
|
+
|
|
342
344
|
brv = binned_statistic(time, rv, statistic=stat, bins=bins, range=None,
|
|
343
345
|
weights=err)
|
|
344
346
|
|
|
@@ -346,6 +348,9 @@ def binRV(time, rv, err=None, stat='wmean', tstat='wmean', estat='addquad',
|
|
|
346
348
|
if (err is not None) and (tstat == 'wmean'):
|
|
347
349
|
tstat = wmean # default is weighted mean
|
|
348
350
|
|
|
351
|
+
if (err is None) and (tstat == 'wmean'):
|
|
352
|
+
tstat = 'mean'
|
|
353
|
+
|
|
349
354
|
times = binned_statistic(time, time, statistic=tstat, bins=bins,
|
|
350
355
|
range=None, weights=err)
|
|
351
356
|
# if there are errors, bin them too
|
|
@@ -23,7 +23,7 @@ def load_spectroscopy() -> SpectroscopyClass:
|
|
|
23
23
|
|
|
24
24
|
@lru_cache()
|
|
25
25
|
def get_dace_id(star):
|
|
26
|
-
filters = {"obj_id_catname": {"
|
|
26
|
+
filters = {"obj_id_catname": {"equal": [star]}}
|
|
27
27
|
try:
|
|
28
28
|
with stdout_disabled(), all_logging_disabled():
|
|
29
29
|
r = load_spectroscopy().query_database(filters=filters, limit=1)
|
|
@@ -26,7 +26,7 @@ def run_query(query):
|
|
|
26
26
|
url = 'https://gea.esac.esa.int/tap-server/tap/sync'
|
|
27
27
|
data = dict(query=query, request='doQuery', lang='ADQL', format='csv')
|
|
28
28
|
try:
|
|
29
|
-
response = requests.post(url, data=data, timeout=
|
|
29
|
+
response = requests.post(url, data=data, timeout=5)
|
|
30
30
|
except requests.ReadTimeout as err:
|
|
31
31
|
raise IndexError(err)
|
|
32
32
|
except requests.ConnectionError as err:
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
from functools import partial, partialmethod
|
|
1
|
+
from functools import partialmethod, wraps
|
|
3
2
|
from itertools import cycle
|
|
4
3
|
|
|
5
|
-
import matplotlib.collections
|
|
6
4
|
import numpy as np
|
|
7
|
-
import matplotlib
|
|
8
|
-
import matplotlib.pyplot as plt
|
|
9
|
-
import mplcursors
|
|
10
5
|
|
|
11
6
|
from astropy.timeseries import LombScargle
|
|
12
7
|
|
|
@@ -14,11 +9,24 @@ from .setup_logger import logger
|
|
|
14
9
|
from . import config
|
|
15
10
|
from .stats import wmean
|
|
16
11
|
|
|
12
|
+
from .utils import lazy_import
|
|
13
|
+
plt = lazy_import('matplotlib.pyplot')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def plot_fast(func):
|
|
17
|
+
@wraps(func)
|
|
18
|
+
def wrapper(*args, **kwargs):
|
|
19
|
+
with plt.style.context('fast'):
|
|
20
|
+
return func(*args, **kwargs)
|
|
21
|
+
return wrapper
|
|
22
|
+
|
|
23
|
+
|
|
17
24
|
|
|
18
25
|
class BlittedCursor:
|
|
19
26
|
""" A cross-hair cursor using blitting for faster redraw. """
|
|
20
27
|
def __init__(self, axes, vertical=True, horizontal=True, show_text=None,
|
|
21
28
|
transforms_x=None, transforms_y=None):
|
|
29
|
+
import matplotlib # delay import
|
|
22
30
|
if isinstance(axes, matplotlib.axes.Axes):
|
|
23
31
|
axes = [axes]
|
|
24
32
|
self.axes = axes
|
|
@@ -102,10 +110,31 @@ class BlittedCursor:
|
|
|
102
110
|
ax.draw_artist(self.text)
|
|
103
111
|
ax.figure.canvas.blit(ax.bbox)
|
|
104
112
|
|
|
113
|
+
def clickable_legend(fig, ax, leg):
|
|
114
|
+
from matplotlib.text import Text
|
|
115
|
+
handles, labels = ax.get_legend_handles_labels()
|
|
116
|
+
for text in leg.get_texts():
|
|
117
|
+
text.set_picker(True)
|
|
105
118
|
|
|
119
|
+
def on_pick_legend(event):
|
|
120
|
+
artist = event.artist
|
|
121
|
+
if isinstance(artist, Text):
|
|
122
|
+
try:
|
|
123
|
+
h = handles[labels.index(artist.get_text())]
|
|
124
|
+
alpha_text = {None:0.2, 1.0: 0.2, 0.2:1.0}[artist.get_alpha()]
|
|
125
|
+
alpha_point = {None: 0.0, 1.0: 0.0, 0.2: 1.0}[artist.get_alpha()]
|
|
126
|
+
h[0].set_alpha(alpha_point)
|
|
127
|
+
h[2][0].set_alpha(alpha_point)
|
|
128
|
+
artist.set_alpha(alpha_text)
|
|
129
|
+
fig.canvas.draw()
|
|
130
|
+
except ValueError:
|
|
131
|
+
pass
|
|
132
|
+
return on_pick_legend
|
|
133
|
+
|
|
134
|
+
# @plot_fast
|
|
106
135
|
def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
107
|
-
remove_50000=False, tooltips=False,
|
|
108
|
-
versus_n=False, show_histogram=False, bw=False, **kwargs):
|
|
136
|
+
remove_50000=False, tooltips=False, show_legend=True, label=None,
|
|
137
|
+
N_in_label=False, versus_n=False, show_histogram=False, bw=False, **kwargs):
|
|
109
138
|
""" Plot the RVs
|
|
110
139
|
|
|
111
140
|
Args:
|
|
@@ -121,6 +150,8 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
121
150
|
Whether to subtract 50000 from time. Defaults to False.
|
|
122
151
|
tooltips (bool, optional):
|
|
123
152
|
Show information upon clicking a point. Defaults to True.
|
|
153
|
+
show_legend (bool, optional):
|
|
154
|
+
Show legend. Defaults to True.
|
|
124
155
|
N_in_label (bool, optional):
|
|
125
156
|
Show number of observations in legend. Defaults to False.
|
|
126
157
|
versus_n (bool, optional):
|
|
@@ -145,12 +176,14 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
145
176
|
fig, (ax, axh) = plt.subplots(1, 2, constrained_layout=True, gridspec_kw={'width_ratios': [3, 1]})
|
|
146
177
|
else:
|
|
147
178
|
fig, ax = plt.subplots(1, 1, constrained_layout=True)
|
|
179
|
+
elif ax == -1:
|
|
180
|
+
ax = plt.gca()
|
|
181
|
+
fig = ax.figure
|
|
148
182
|
else:
|
|
149
183
|
if show_histogram:
|
|
150
184
|
ax, axh = ax
|
|
151
185
|
fig = ax.figure
|
|
152
186
|
|
|
153
|
-
|
|
154
187
|
kwargs.setdefault('ls', '')
|
|
155
188
|
kwargs.setdefault('capsize', 0)
|
|
156
189
|
kwargs.setdefault('ms', 4)
|
|
@@ -172,7 +205,6 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
172
205
|
except AttributeError:
|
|
173
206
|
zorders = cycle([1] * len(instruments))
|
|
174
207
|
|
|
175
|
-
cursors = {}
|
|
176
208
|
containers = {}
|
|
177
209
|
for _i, inst in enumerate(instruments):
|
|
178
210
|
s = self if self._child else getattr(self, inst)
|
|
@@ -207,22 +239,6 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
207
239
|
hlabel = f'{s.mvrad.std():.2f} {self.units}'
|
|
208
240
|
axh.hist(s.mvrad, **kw, label=hlabel)
|
|
209
241
|
|
|
210
|
-
# cursors[inst] = crsr = mplcursors.cursor(container, multiple=False)
|
|
211
|
-
# @crsr.connect("add")
|
|
212
|
-
# def _(sel):
|
|
213
|
-
# inst = sel.artist.get_label()
|
|
214
|
-
# _s = getattr(self, inst)
|
|
215
|
-
# vrad, svrad = _s.vrad[sel.index], _s.svrad[sel.index]
|
|
216
|
-
# sel.annotation.get_bbox_patch().set(fc="white")
|
|
217
|
-
# text = f'{inst}\n'
|
|
218
|
-
# text += f'BJD: {sel.target[0]:9.5f}\n'
|
|
219
|
-
# text += f'RV: {vrad:.3f} ± {svrad:.3f}'
|
|
220
|
-
# # if fig.canvas.manager.toolmanager.get_tool('infotool').toggled:
|
|
221
|
-
# # text += '\n\n'
|
|
222
|
-
# # text += f'date: {_s.date_night[sel.index]}\n'
|
|
223
|
-
# # text += f'mask: {_s.ccf_mask[sel.index]}'
|
|
224
|
-
# sel.annotation.set_text(text)
|
|
225
|
-
|
|
226
242
|
if show_masked:
|
|
227
243
|
if versus_n:
|
|
228
244
|
pass
|
|
@@ -239,62 +255,104 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
239
255
|
ax.errorbar(self.time[~self.mask] - time_offset, self.vrad[~self.mask], self.svrad[~self.mask],
|
|
240
256
|
label='masked', fmt='x', ms=10, color='k', zorder=-2)
|
|
241
257
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def on_pick_legend(event):
|
|
248
|
-
artist = event.artist
|
|
249
|
-
if isinstance(artist, matplotlib.text.Text):
|
|
250
|
-
try:
|
|
251
|
-
h = handles[labels.index(artist.get_text())]
|
|
252
|
-
alpha_text = {None:0.2, 1.0: 0.2, 0.2:1.0}[artist.get_alpha()]
|
|
253
|
-
alpha_point = {None: 0.0, 1.0: 0.0, 0.2: 1.0}[artist.get_alpha()]
|
|
254
|
-
h[0].set_alpha(alpha_point)
|
|
255
|
-
h[2][0].set_alpha(alpha_point)
|
|
256
|
-
artist.set_alpha(alpha_text)
|
|
257
|
-
fig.canvas.draw()
|
|
258
|
-
except ValueError:
|
|
259
|
-
pass
|
|
260
|
-
plt.connect('pick_event', on_pick_legend)
|
|
258
|
+
if show_legend:
|
|
259
|
+
leg = ax.legend()
|
|
260
|
+
on_pick_legend = clickable_legend(fig, ax, leg)
|
|
261
|
+
plt.connect('pick_event', on_pick_legend)
|
|
261
262
|
|
|
262
263
|
if tooltips:
|
|
264
|
+
from matplotlib.lines import Line2D
|
|
265
|
+
from matplotlib.collections import LineCollection
|
|
263
266
|
annotations = []
|
|
264
|
-
|
|
265
|
-
|
|
267
|
+
axes_artists = []
|
|
268
|
+
selected_inds = []
|
|
269
|
+
selected_insts = []
|
|
270
|
+
|
|
271
|
+
def _cleanup():
|
|
266
272
|
for text in annotations:
|
|
267
273
|
text.remove()
|
|
268
274
|
annotations.remove(text)
|
|
275
|
+
for art in axes_artists:
|
|
276
|
+
art.remove()
|
|
277
|
+
axes_artists.remove(art)
|
|
278
|
+
for ind in selected_inds:
|
|
279
|
+
selected_inds.remove(ind)
|
|
280
|
+
|
|
281
|
+
def on_press(event):
|
|
282
|
+
# print('press', event.key)
|
|
283
|
+
if event.key in ('r',):
|
|
284
|
+
for i, inst in zip(selected_inds, selected_insts):
|
|
285
|
+
i = self._index_from_instrument_index(i, inst)
|
|
286
|
+
self.remove_point(i)
|
|
287
|
+
_cleanup()
|
|
288
|
+
fig.canvas.draw_idle()
|
|
289
|
+
if event.key == 'escape':
|
|
290
|
+
_cleanup()
|
|
291
|
+
kp_cid = None
|
|
292
|
+
for k, _f in fig.canvas.callbacks.callbacks['key_press_event'].items():
|
|
293
|
+
if _f._obj == on_press:
|
|
294
|
+
kp_cid = k
|
|
295
|
+
if kp_cid is not None:
|
|
296
|
+
fig.canvas.callbacks.disconnect(k)
|
|
297
|
+
fig.canvas.draw_idle()
|
|
269
298
|
|
|
299
|
+
def on_pick_point(event):
|
|
300
|
+
_cleanup()
|
|
270
301
|
artist = event.artist
|
|
271
|
-
if isinstance(artist, (
|
|
272
|
-
print(event.ind, artist)
|
|
273
|
-
if isinstance(artist,
|
|
302
|
+
if isinstance(artist, (Line2D, LineCollection)):
|
|
303
|
+
# print(event.ind, artist)
|
|
304
|
+
if isinstance(artist, Line2D):
|
|
305
|
+
ind = event.ind
|
|
274
306
|
matching_instrument = [k for k, v in containers.items() if artist in v]
|
|
275
|
-
print(matching_instrument)
|
|
276
307
|
if len(matching_instrument) == 0:
|
|
277
308
|
return
|
|
278
309
|
inst = matching_instrument[0]
|
|
310
|
+
|
|
279
311
|
_s = getattr(self, inst)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
|
|
313
|
+
if event.ind.size > 1:
|
|
314
|
+
mint, maxt = _s.mtime[ind].min(), _s.mtime[ind].max()
|
|
315
|
+
miny, maxy = _s.mvrad[ind].min(), _s.mvrad[ind].max()
|
|
316
|
+
axins = ax.inset_axes([0.1, 0.5, 0.5, 0.4],
|
|
317
|
+
xlim=(mint - 0.1 * (maxt - mint), maxt + 0.1 * (maxt - mint)),
|
|
318
|
+
ylim=(miny - 0.1 * (maxy - miny), maxy + 0.1 * (maxy - miny)),
|
|
319
|
+
xticklabels=[], yticklabels=[]
|
|
320
|
+
)
|
|
321
|
+
axins.errorbar(_s.mtime[ind], _s.mvrad[ind], _s.msvrad[ind], fmt='o', ms=3,
|
|
322
|
+
color=artist.get_color())
|
|
323
|
+
axins.margins(x=0.5)
|
|
324
|
+
axins.autoscale_view()
|
|
325
|
+
rectangle_patch, connector_lines = ax.indicate_inset_zoom(axins, edgecolor="black")
|
|
326
|
+
axes_artists.append(axins)
|
|
327
|
+
axes_artists.append(rectangle_patch)
|
|
328
|
+
for line in connector_lines:
|
|
329
|
+
axes_artists.append(line)
|
|
330
|
+
else:
|
|
331
|
+
ind = event.ind[0]
|
|
332
|
+
selected_inds.append(ind)
|
|
333
|
+
selected_insts.append(inst)
|
|
334
|
+
# print(_s.mtime[ind], _s.mvrad[ind], _s.msvrad[ind])
|
|
335
|
+
|
|
336
|
+
text = f'{inst} ({ind})\n'
|
|
337
|
+
text += f'{_s.mtime[ind]:9.5f}\n'
|
|
338
|
+
text += f'RV: {_s.mvrad[ind]:.1f} ± {_s.msvrad[ind]:.1f}'
|
|
339
|
+
|
|
340
|
+
annotations.append(
|
|
341
|
+
ax.annotate(text, (_s.mtime[ind], _s.mvrad[ind]), xycoords='data',
|
|
342
|
+
xytext=(5, 10), textcoords='offset points', fontsize=9,
|
|
343
|
+
bbox={'boxstyle': 'round', 'fc': 'w'}, arrowprops=dict(arrowstyle="-"))
|
|
344
|
+
)
|
|
292
345
|
# ax.annotate(f'{inst}', (0.5, 0.5), xycoords=artist, ha='center', va='center')
|
|
293
346
|
fig.canvas.draw()
|
|
294
347
|
# print(event.ind, artist.get_label())
|
|
348
|
+
|
|
349
|
+
_ = fig.canvas.mpl_connect('key_press_event', on_press)
|
|
350
|
+
|
|
295
351
|
plt.connect('pick_event', on_pick_point)
|
|
296
352
|
|
|
297
353
|
|
|
354
|
+
|
|
355
|
+
|
|
298
356
|
if show_histogram:
|
|
299
357
|
axh.legend()
|
|
300
358
|
|
|
@@ -309,25 +367,23 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
309
367
|
else:
|
|
310
368
|
ax.set_xlabel('BJD - 2400000 [days]')
|
|
311
369
|
|
|
312
|
-
from matplotlib.backend_tools import ToolBase, ToolToggleBase
|
|
313
|
-
tm = fig.canvas.manager.toolmanager
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
except
|
|
328
|
-
|
|
329
|
-
except UnidentifiedImageError:
|
|
330
|
-
pass
|
|
370
|
+
# from matplotlib.backend_tools import ToolBase, ToolToggleBase
|
|
371
|
+
# tm = fig.canvas.manager.toolmanager
|
|
372
|
+
# class InfoTool(ToolToggleBase):
|
|
373
|
+
# description = "Show extra information about each observation"
|
|
374
|
+
# image = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'info.svg'))
|
|
375
|
+
# # def enable(self, *args, **kwargs):
|
|
376
|
+
# # self.figure.add_axes([1, 0, 0.3, 1])
|
|
377
|
+
# # self.figure.canvas.draw_idle()
|
|
378
|
+
# from PIL import UnidentifiedImageError
|
|
379
|
+
# try:
|
|
380
|
+
# tm.add_tool("infotool", InfoTool)
|
|
381
|
+
# fig.canvas.manager.toolbar.add_tool(tm.get_tool("infotool"), "toolgroup")
|
|
382
|
+
# raise UnidentifiedImageError
|
|
383
|
+
# except AttributeError:
|
|
384
|
+
# pass
|
|
385
|
+
# except UnidentifiedImageError:
|
|
386
|
+
# pass
|
|
331
387
|
|
|
332
388
|
|
|
333
389
|
if config.return_self:
|
|
@@ -339,8 +395,9 @@ def plot(self, ax=None, show_masked=False, instrument=None, time_offset=0,
|
|
|
339
395
|
return fig, ax
|
|
340
396
|
|
|
341
397
|
|
|
398
|
+
@plot_fast
|
|
342
399
|
def plot_quantity(self, quantity, ax=None, show_masked=False, instrument=None,
|
|
343
|
-
time_offset=0, remove_50000=False, tooltips=False,
|
|
400
|
+
time_offset=0, remove_50000=False, tooltips=False, show_legend=True,
|
|
344
401
|
N_in_label=False, **kwargs):
|
|
345
402
|
if self.N == 0:
|
|
346
403
|
if self.verbose:
|
|
@@ -399,17 +456,21 @@ def plot_quantity(self, quantity, ax=None, show_masked=False, instrument=None,
|
|
|
399
456
|
getattr(self, quantity + '_err')[~self.mask],
|
|
400
457
|
label='masked', fmt='x', ms=10, color='k', zorder=-2)
|
|
401
458
|
|
|
402
|
-
|
|
459
|
+
if show_legend:
|
|
460
|
+
leg = ax.legend()
|
|
461
|
+
on_pick_legend = clickable_legend(fig, ax, leg)
|
|
462
|
+
plt.connect('pick_event', on_pick_legend)
|
|
463
|
+
|
|
403
464
|
ax.minorticks_on()
|
|
404
465
|
|
|
405
466
|
ylabel = {
|
|
467
|
+
quantity: quantity,
|
|
406
468
|
'fwhm': f'FWHM [{self.units}]',
|
|
407
469
|
'bispan': f'BIS [{self.units}]',
|
|
408
470
|
'rhk': r"$\log$ R'$_{HK}$",
|
|
409
|
-
'berv':
|
|
410
|
-
quantity: quantity,
|
|
471
|
+
'berv': 'BERV [km/s]',
|
|
411
472
|
}
|
|
412
|
-
ax.set_ylabel(ylabel[quantity])
|
|
473
|
+
ax.set_ylabel(ylabel[quantity.lower()])
|
|
413
474
|
|
|
414
475
|
if remove_50000:
|
|
415
476
|
ax.set_xlabel('BJD - 2450000 [days]')
|
|
@@ -428,6 +489,7 @@ plot_rhk = partialmethod(plot_quantity, quantity='rhk')
|
|
|
428
489
|
plot_berv = partialmethod(plot_quantity, quantity='berv')
|
|
429
490
|
|
|
430
491
|
|
|
492
|
+
@plot_fast
|
|
431
493
|
def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=config.adjust_means_gls,
|
|
432
494
|
picker=True, **kwargs):
|
|
433
495
|
"""
|
|
@@ -471,7 +533,7 @@ def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=confi
|
|
|
471
533
|
if self.verbose:
|
|
472
534
|
logger.info(f'calculating periodogram for instrument {instrument}')
|
|
473
535
|
|
|
474
|
-
if adjust_means:
|
|
536
|
+
if adjust_means and not self._child:
|
|
475
537
|
if self.verbose:
|
|
476
538
|
logger.info('adjusting instrument means before gls')
|
|
477
539
|
means = np.empty_like(y)
|
|
@@ -486,7 +548,7 @@ def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=confi
|
|
|
486
548
|
y = self.vrad[self.mask].copy()
|
|
487
549
|
e = self.svrad[self.mask].copy()
|
|
488
550
|
|
|
489
|
-
if adjust_means:
|
|
551
|
+
if adjust_means and not self._child:
|
|
490
552
|
if self.verbose:
|
|
491
553
|
logger.info('adjusting instrument means before gls')
|
|
492
554
|
means = np.empty_like(y)
|
|
@@ -529,6 +591,7 @@ def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=confi
|
|
|
529
591
|
ax.legend()
|
|
530
592
|
|
|
531
593
|
if ax.get_legend() is not None:
|
|
594
|
+
from matplotlib.text import Text
|
|
532
595
|
leg = ax.get_legend()
|
|
533
596
|
for text in leg.get_texts():
|
|
534
597
|
text.set_picker(True)
|
|
@@ -536,7 +599,7 @@ def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=confi
|
|
|
536
599
|
def on_pick_legend(event):
|
|
537
600
|
handles, labels = ax.get_legend_handles_labels()
|
|
538
601
|
artist = event.artist
|
|
539
|
-
if isinstance(artist,
|
|
602
|
+
if isinstance(artist, Text):
|
|
540
603
|
# print('handles:', handles)
|
|
541
604
|
# print('labels:', labels)
|
|
542
605
|
# print(artist.get_text())
|
|
@@ -560,6 +623,7 @@ def gls(self, ax=None, label=None, fap=True, instrument=None, adjust_means=confi
|
|
|
560
623
|
return fig, ax
|
|
561
624
|
|
|
562
625
|
|
|
626
|
+
@plot_fast
|
|
563
627
|
def gls_quantity(self, quantity, ax=None, fap=True, picker=True):
|
|
564
628
|
if not hasattr(self, quantity):
|
|
565
629
|
logger.error(f"cannot find '{quantity}' attribute")
|
|
@@ -572,7 +636,10 @@ def gls_quantity(self, quantity, ax=None, fap=True, picker=True):
|
|
|
572
636
|
|
|
573
637
|
t = self.mtime
|
|
574
638
|
y = getattr(self, quantity)[self.mask]
|
|
575
|
-
|
|
639
|
+
try:
|
|
640
|
+
ye = getattr(self, quantity + '_err')[self.mask]
|
|
641
|
+
except AttributeError:
|
|
642
|
+
ye = None
|
|
576
643
|
|
|
577
644
|
if np.isnan(y).any():
|
|
578
645
|
if self.verbose:
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
from functools import partial
|
|
2
2
|
import numpy as np
|
|
3
3
|
from astropy.timeseries import LombScargle
|
|
4
|
-
import matplotlib.pyplot as plt
|
|
5
|
-
import matplotlib.gridspec as gridspec
|
|
6
|
-
from matplotlib.backends.backend_pdf import PdfPages
|
|
7
4
|
|
|
8
5
|
from .setup_logger import logger
|
|
9
6
|
|
|
@@ -31,6 +28,10 @@ def sine_picker(event, self, fig, ax, ax1):
|
|
|
31
28
|
|
|
32
29
|
|
|
33
30
|
def report(self, save=None):
|
|
31
|
+
import matplotlib.pyplot as plt
|
|
32
|
+
import matplotlib.gridspec as gridspec
|
|
33
|
+
from matplotlib.backends.backend_pdf import PdfPages
|
|
34
|
+
|
|
34
35
|
# size = A4
|
|
35
36
|
size = 8.27, 11.69
|
|
36
37
|
fig = plt.figure(figsize=size, constrained_layout=True)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import requests
|
|
3
3
|
|
|
4
|
-
from astropy.coordinates import SkyCoord
|
|
5
4
|
import pysweetcat
|
|
6
5
|
|
|
7
6
|
DATA_PATH = os.path.dirname(__file__)
|
|
@@ -44,7 +43,7 @@ def run_query(query):
|
|
|
44
43
|
url = 'http://simbad.u-strasbg.fr/simbad/sim-tap/sync'
|
|
45
44
|
data = dict(query=query, request='doQuery', lang='ADQL', format='text/plain', phase='run')
|
|
46
45
|
try:
|
|
47
|
-
response = requests.post(url, data=data, timeout=
|
|
46
|
+
response = requests.post(url, data=data, timeout=5)
|
|
48
47
|
except requests.ReadTimeout as err:
|
|
49
48
|
raise IndexError(err)
|
|
50
49
|
except requests.ConnectionError as err:
|
|
@@ -97,6 +96,8 @@ class simbad:
|
|
|
97
96
|
Args:
|
|
98
97
|
star (str): The name of the star to query simbad
|
|
99
98
|
"""
|
|
99
|
+
from astropy.coordinates import SkyCoord
|
|
100
|
+
|
|
100
101
|
self.star = star
|
|
101
102
|
|
|
102
103
|
if 'kobe' in self.star.lower():
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
from scipy.stats import median_abs_deviation
|
|
3
|
-
from scipy.stats._stats_py import SigmaclipResult
|
|
4
|
-
|
|
5
2
|
|
|
6
3
|
def wmean(a, e):
|
|
7
4
|
"""Weighted mean of array `a`, with uncertainties given by `e`.
|
|
@@ -69,6 +66,8 @@ def sigmaclip_median(a, low=4.0, high=4.0):
|
|
|
69
66
|
- `lower`: Lower clipping limit
|
|
70
67
|
- `upper`: Upper clipping limit
|
|
71
68
|
"""
|
|
69
|
+
from scipy.stats import median_abs_deviation
|
|
70
|
+
from scipy.stats._stats_py import SigmaclipResult
|
|
72
71
|
c = np.asarray(a).ravel()
|
|
73
72
|
delta = 1
|
|
74
73
|
while delta:
|
|
@@ -122,6 +122,19 @@ def find_data_file(file):
|
|
|
122
122
|
|
|
123
123
|
return data_file
|
|
124
124
|
|
|
125
|
+
|
|
126
|
+
import importlib.util
|
|
127
|
+
import sys
|
|
128
|
+
def lazy_import(name):
|
|
129
|
+
spec = importlib.util.find_spec(name)
|
|
130
|
+
loader = importlib.util.LazyLoader(spec.loader)
|
|
131
|
+
spec.loader = loader
|
|
132
|
+
module = importlib.util.module_from_spec(spec)
|
|
133
|
+
sys.modules[name] = module
|
|
134
|
+
loader.exec_module(module)
|
|
135
|
+
return module
|
|
136
|
+
|
|
137
|
+
|
|
125
138
|
def ESPRESSO_ADC_issues():
|
|
126
139
|
adc_file = find_data_file('obs_affected_ADC_issues.dat')
|
|
127
140
|
lines = [line.strip() for line in open(adc_file).readlines()]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arvi
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: The Automated RV Inspector
|
|
5
5
|
Author-email: João Faria <joao.faria@unige.ch>
|
|
6
6
|
License: MIT
|
|
@@ -14,11 +14,9 @@ Requires-Dist: mock; python_version < "3.3"
|
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: scipy
|
|
16
16
|
Requires-Dist: matplotlib
|
|
17
|
-
Requires-Dist: mplcursors
|
|
18
17
|
Requires-Dist: astropy
|
|
19
18
|
Requires-Dist: dace-query
|
|
20
19
|
Requires-Dist: loguru
|
|
21
|
-
Requires-Dist: mpldatacursor
|
|
22
20
|
Requires-Dist: tqdm
|
|
23
21
|
Requires-Dist: pySWEETCat
|
|
24
22
|
Requires-Dist: kepmodel
|
|
@@ -8,7 +8,7 @@ authors = [
|
|
|
8
8
|
{name = "João Faria", email = "joao.faria@unige.ch"},
|
|
9
9
|
]
|
|
10
10
|
description = "The Automated RV Inspector"
|
|
11
|
-
version = "0.1.
|
|
11
|
+
version = "0.1.15"
|
|
12
12
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
13
13
|
requires-python = ">=3.8"
|
|
14
14
|
keywords = ["RV", "exoplanets"]
|
|
@@ -22,11 +22,9 @@ dependencies = [
|
|
|
22
22
|
"numpy",
|
|
23
23
|
"scipy",
|
|
24
24
|
"matplotlib",
|
|
25
|
-
"mplcursors",
|
|
26
25
|
"astropy",
|
|
27
26
|
"dace-query",
|
|
28
27
|
"loguru",
|
|
29
|
-
"mpldatacursor",
|
|
30
28
|
"tqdm",
|
|
31
29
|
"pySWEETCat",
|
|
32
30
|
"kepmodel",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|