arvi 0.1.14__tar.gz → 0.1.16__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.

Files changed (55) hide show
  1. {arvi-0.1.14 → arvi-0.1.16}/.github/workflows/python-publish.yml +2 -2
  2. {arvi-0.1.14 → arvi-0.1.16}/PKG-INFO +1 -3
  3. {arvi-0.1.14 → arvi-0.1.16}/arvi/binning.py +14 -9
  4. {arvi-0.1.14 → arvi-0.1.16}/arvi/dace_wrapper.py +6 -10
  5. {arvi-0.1.14 → arvi-0.1.16}/arvi/gaia_wrapper.py +1 -1
  6. {arvi-0.1.14 → arvi-0.1.16}/arvi/plots.py +158 -91
  7. {arvi-0.1.14 → arvi-0.1.16}/arvi/reports.py +4 -3
  8. {arvi-0.1.14 → arvi-0.1.16}/arvi/simbad_wrapper.py +3 -2
  9. {arvi-0.1.14 → arvi-0.1.16}/arvi/stats.py +2 -3
  10. {arvi-0.1.14 → arvi-0.1.16}/arvi/utils.py +13 -0
  11. {arvi-0.1.14 → arvi-0.1.16}/arvi.egg-info/PKG-INFO +1 -3
  12. {arvi-0.1.14 → arvi-0.1.16}/arvi.egg-info/requires.txt +0 -2
  13. {arvi-0.1.14 → arvi-0.1.16}/pyproject.toml +1 -3
  14. {arvi-0.1.14 → arvi-0.1.16}/.github/workflows/docs-gh-pages.yml +0 -0
  15. {arvi-0.1.14 → arvi-0.1.16}/.github/workflows/install.yml +0 -0
  16. {arvi-0.1.14 → arvi-0.1.16}/.gitignore +0 -0
  17. {arvi-0.1.14 → arvi-0.1.16}/LICENSE +0 -0
  18. {arvi-0.1.14 → arvi-0.1.16}/README.md +0 -0
  19. {arvi-0.1.14 → arvi-0.1.16}/arvi/HZ.py +0 -0
  20. {arvi-0.1.14 → arvi-0.1.16}/arvi/__init__.py +0 -0
  21. {arvi-0.1.14 → arvi-0.1.16}/arvi/ariadne_wrapper.py +0 -0
  22. {arvi-0.1.14 → arvi-0.1.16}/arvi/berv.py +0 -0
  23. {arvi-0.1.14 → arvi-0.1.16}/arvi/config.py +0 -0
  24. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/extra/HD86226_PFS1.rdb +0 -0
  25. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/extra/HD86226_PFS2.rdb +0 -0
  26. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/extra/metadata.json +0 -0
  27. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/info.svg +0 -0
  28. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/obs_affected_ADC_issues.dat +0 -0
  29. {arvi-0.1.14 → arvi-0.1.16}/arvi/data/obs_affected_blue_cryostat_issues.dat +0 -0
  30. {arvi-0.1.14 → arvi-0.1.16}/arvi/extra_data.py +0 -0
  31. {arvi-0.1.14 → arvi-0.1.16}/arvi/headers.py +0 -0
  32. {arvi-0.1.14 → arvi-0.1.16}/arvi/instrument_specific.py +0 -0
  33. {arvi-0.1.14 → arvi-0.1.16}/arvi/lbl_wrapper.py +0 -0
  34. {arvi-0.1.14 → arvi-0.1.16}/arvi/nasaexo_wrapper.py +0 -0
  35. {arvi-0.1.14 → arvi-0.1.16}/arvi/programs.py +0 -0
  36. {arvi-0.1.14 → arvi-0.1.16}/arvi/setup_logger.py +0 -0
  37. {arvi-0.1.14 → arvi-0.1.16}/arvi/spectra.py +0 -0
  38. {arvi-0.1.14 → arvi-0.1.16}/arvi/stellar.py +0 -0
  39. {arvi-0.1.14 → arvi-0.1.16}/arvi/timeseries.py +0 -0
  40. {arvi-0.1.14 → arvi-0.1.16}/arvi/translations.py +0 -0
  41. {arvi-0.1.14 → arvi-0.1.16}/arvi.egg-info/SOURCES.txt +0 -0
  42. {arvi-0.1.14 → arvi-0.1.16}/arvi.egg-info/dependency_links.txt +0 -0
  43. {arvi-0.1.14 → arvi-0.1.16}/arvi.egg-info/top_level.txt +0 -0
  44. {arvi-0.1.14 → arvi-0.1.16}/docs/API.md +0 -0
  45. {arvi-0.1.14 → arvi-0.1.16}/docs/detailed.md +0 -0
  46. {arvi-0.1.14 → arvi-0.1.16}/docs/index.md +0 -0
  47. {arvi-0.1.14 → arvi-0.1.16}/docs/logo/detective.png +0 -0
  48. {arvi-0.1.14 → arvi-0.1.16}/docs/logo/logo.png +0 -0
  49. {arvi-0.1.14 → arvi-0.1.16}/mkdocs.yml +0 -0
  50. {arvi-0.1.14 → arvi-0.1.16}/setup.cfg +0 -0
  51. {arvi-0.1.14 → arvi-0.1.16}/setup.py +0 -0
  52. {arvi-0.1.14 → arvi-0.1.16}/tests/test_binning.py +0 -0
  53. {arvi-0.1.14 → arvi-0.1.16}/tests/test_import_object.py +0 -0
  54. {arvi-0.1.14 → arvi-0.1.16}/tests/test_simbad.py +0 -0
  55. {arvi-0.1.14 → arvi-0.1.16}/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@v3
25
+ - uses: actions/checkout@v4
26
26
  - name: Set up Python
27
- uses: actions/setup-python@v3
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.14
3
+ Version: 0.1.16
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
- doc1 = old_binned_statistic.__doc__
219
- doc2 = old_binned_statistic_dd.__doc__
220
- binned_statistic.__doc__ = doc1
221
- binned_statistic_dd.__doc__ = doc2
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": {"contains": [star]}}
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)
@@ -36,10 +36,6 @@ def get_arrays(result, latest_pipeline=True, ESPRESSO_mode='HR11', NIRPS_mode='H
36
36
  arrays = []
37
37
  instruments = list(result.keys())
38
38
 
39
- # if verbose:
40
- # if latest_pipeline:
41
- # logger.info('selecting latest pipeline version')
42
-
43
39
  for inst in instruments:
44
40
  pipelines = list(result[inst].keys())
45
41
 
@@ -226,11 +222,12 @@ def get_observations(star, instrument=None, main_id=None, verbose=True):
226
222
  raise ValueError(msg)
227
223
 
228
224
  # sort pipelines, being extra careful with HARPS pipeline names
229
- # (i.e. ensure that 3.0.0 > 3.5)
225
+ # (i.e. ensure that 3.x.x > 3.5)
226
+ from re import match
230
227
  def cmp(a, b):
231
- if a[0] in ('3.5', '3.5 EGGS') and b[0] == '3.0.0':
228
+ if a[0] in ('3.5', '3.5 EGGS') and match(r'3.\d.\d', b[0]):
232
229
  return -1
233
- if b[0] in ('3.5', '3.5 EGGS') and a[0] == '3.0.0':
230
+ if b[0] in ('3.5', '3.5 EGGS') and match(r'3.\d.\d', a[0]):
234
231
  return 1
235
232
 
236
233
  if a[0] == b[0]:
@@ -243,8 +240,7 @@ def get_observations(star, instrument=None, main_id=None, verbose=True):
243
240
  from functools import cmp_to_key
244
241
  new_result = {}
245
242
  for inst in instruments:
246
- new_result[inst] = dict(sorted(result[inst].items(),
247
- key=cmp_to_key(cmp), reverse=True))
243
+ new_result[inst] = dict(sorted(result[inst].items(), key=cmp_to_key(cmp), reverse=True))
248
244
 
249
245
  if verbose:
250
246
  logger.info('RVs available from')
@@ -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=10)
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 os
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, label=None, N_in_label=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
- leg = ax.legend()
243
- handles, labels = ax.get_legend_handles_labels()
244
- for text in leg.get_texts():
245
- text.set_picker(True)
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
- def on_pick_point(event):
265
- print('annotations:', annotations)
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, (matplotlib.lines.Line2D, matplotlib.collections.LineCollection)):
272
- print(event.ind, artist)
273
- if isinstance(artist, matplotlib.lines.Line2D):
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
- ind = event.ind[0]
281
- # print(_s.mtime[ind], _s.mvrad[ind], _s.msvrad[ind])
282
-
283
- text = f'{inst}\n'
284
- text += f'{_s.mtime[ind]:9.5f}\n'
285
- text += f'RV: {_s.mvrad[ind]:.1f} ± {_s.msvrad[ind]:.1f}'
286
-
287
- annotations.append(
288
- ax.annotate(text, (_s.mtime[ind], _s.mvrad[ind]), xycoords='data',
289
- xytext=(5, 10), textcoords='offset points', fontsize=9,
290
- bbox={'boxstyle': 'round', 'fc': 'w'}, arrowprops=dict(arrowstyle="-"))
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
- class InfoTool(ToolToggleBase):
316
- description = "Show extra information about each observation"
317
- image = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'info.svg'))
318
- # def enable(self, *args, **kwargs):
319
- # self.figure.add_axes([1, 0, 0.3, 1])
320
- # self.figure.canvas.draw_idle()
321
-
322
- from PIL import UnidentifiedImageError
323
- try:
324
- tm.add_tool("infotool", InfoTool)
325
- fig.canvas.manager.toolbar.add_tool(tm.get_tool("infotool"), "toolgroup")
326
- raise UnidentifiedImageError
327
- except AttributeError:
328
- pass
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
- ax.legend()
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': f'BERV [km/s]',
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, matplotlib.text.Text):
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
- ye = getattr(self, quantity + '_err')[self.mask]
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=10)
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.14
3
+ Version: 0.1.16
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,11 +1,9 @@
1
1
  numpy
2
2
  scipy
3
3
  matplotlib
4
- mplcursors
5
4
  astropy
6
5
  dace-query
7
6
  loguru
8
- mpldatacursor
9
7
  tqdm
10
8
  pySWEETCat
11
9
  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.14"
11
+ version = "0.1.16"
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