AstroToolkit 1.0.0__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.
- AstroToolkit/Figures/HRD.py +82 -0
- AstroToolkit/Figures/SED.py +364 -0
- AstroToolkit/Figures/__init__.py +0 -0
- AstroToolkit/Miscellaneous/ProperMotionCorrection.py +50 -0
- AstroToolkit/Miscellaneous/ReadFits.py +35 -0
- AstroToolkit/Miscellaneous/TestFile.py +138 -0
- AstroToolkit/Miscellaneous/__init__.py +0 -0
- AstroToolkit/Overlays/Overlay_GALEX.py +148 -0
- AstroToolkit/Overlays/Overlay_Gaia.py +63 -0
- AstroToolkit/Overlays/Overlay_ROSAT.py +20 -0
- AstroToolkit/Overlays/Overlay_Selection.py +42 -0
- AstroToolkit/Overlays/Overlay_ZTF.py +46 -0
- AstroToolkit/Overlays/__init__.py +0 -0
- AstroToolkit/Surveys/DSS.py +153 -0
- AstroToolkit/Surveys/GALEX.py +45 -0
- AstroToolkit/Surveys/Gaia.py +168 -0
- AstroToolkit/Surveys/PanSTARRS.py +221 -0
- AstroToolkit/Surveys/ROSAT.py +51 -0
- AstroToolkit/Surveys/SDSS.py +78 -0
- AstroToolkit/Surveys/SkyMapper.py +215 -0
- AstroToolkit/Surveys/TWOMASS.py +45 -0
- AstroToolkit/Surveys/WISE.py +45 -0
- AstroToolkit/Surveys/ZTF.py +206 -0
- AstroToolkit/Surveys/__init__.py +0 -0
- AstroToolkit/Timeseries/__init__.py +0 -0
- AstroToolkit/Timeseries/pyaov.py +781 -0
- AstroToolkit/Timeseries/ztfanalysis.py +847 -0
- AstroToolkit/Tools.py +1222 -0
- AstroToolkit/__init__.py +0 -0
- AstroToolkit-1.0.0.dist-info/LICENSE +0 -0
- AstroToolkit-1.0.0.dist-info/METADATA +934 -0
- AstroToolkit-1.0.0.dist-info/RECORD +34 -0
- AstroToolkit-1.0.0.dist-info/WHEEL +5 -0
- AstroToolkit-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is a python GUI program to display and analyse a time series. It uses routines developed by
|
|
3
|
+
Alex Schwarzenberg-Czerny to compute periodograms and pre-whitening (and alternatively a Fourier transform
|
|
4
|
+
routine that is included).
|
|
5
|
+
|
|
6
|
+
It can either by called using a command line interface or as a function call:
|
|
7
|
+
The function call (display_light_curve) is completely general and takes an astropy timeseries
|
|
8
|
+
object as its parameter (with specific metadata - see function definition)
|
|
9
|
+
|
|
10
|
+
The command line is designed to process generic data and accepts 2 parameters (filename and path);
|
|
11
|
+
if these are not provided a dialog is initiated to select the values. The last path and format
|
|
12
|
+
used are saved in a .ini file located in the users home directory.
|
|
13
|
+
|
|
14
|
+
In addition there is a test capability that generates a synthetic light curve of two sine waves plus noise.
|
|
15
|
+
This is initiated by changing the value of the variable "test" to 1 and then
|
|
16
|
+
running the program.
|
|
17
|
+
|
|
18
|
+
Prerequisites:
|
|
19
|
+
This is python code using standard modules that
|
|
20
|
+
are included in the Anaconda distribution.
|
|
21
|
+
|
|
22
|
+
It requires the implementation of the "Python GUI for F95 AOV periodogram routines"
|
|
23
|
+
(https://users.camk.edu.pl/alex/) and calls the pyaov package which is included.
|
|
24
|
+
This code has been designed to be portable and should work on
|
|
25
|
+
Linux, Windows and Mac. It has been tested using Python 3.8 under
|
|
26
|
+
Ubuntu 18.04 and also under Windows 10.
|
|
27
|
+
|
|
28
|
+
Coding notes
|
|
29
|
+
This code is based on the QT (version QT5) widget toolkit
|
|
30
|
+
(https://doc.qt.io/qtforpython/). This has been chosen rather than
|
|
31
|
+
Tkinter because it is more portable and provides improved functionality
|
|
32
|
+
(https://dev.to/amigosmaker/python-gui-pyqt-vs-tkinter-5hdd)
|
|
33
|
+
A useful book is https://pythoncourses.gumroad.com/l/pysqtsamples
|
|
34
|
+
|
|
35
|
+
Inevitably the structure of the program is driven by the GUI. display_light_curve
|
|
36
|
+
initiates an instance of Window which will initiate an instance of Window1. Window1
|
|
37
|
+
can initiate an instance of Window2 which in turn can initiate an instance of Window3.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Change history
|
|
45
|
+
|
|
46
|
+
20/10/2022 Keith Inight Initial version
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
import sys
|
|
51
|
+
import os
|
|
52
|
+
from PyQt5.QtWidgets import QDialog, QApplication, QVBoxLayout, QHBoxLayout,\
|
|
53
|
+
QPushButton, QFileDialog, QSpinBox, QLabel, QCheckBox, QButtonGroup, QRadioButton
|
|
54
|
+
from PyQt5.QtCore import QCoreApplication, Qt
|
|
55
|
+
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
|
56
|
+
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
|
|
57
|
+
from matplotlib import gridspec
|
|
58
|
+
import matplotlib.pyplot as plt
|
|
59
|
+
import numpy as np
|
|
60
|
+
from numpy.polynomial import Chebyshev
|
|
61
|
+
from astropy.convolution import convolve, Box1DKernel
|
|
62
|
+
from sklearn.gaussian_process import GaussianProcessRegressor
|
|
63
|
+
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C, WhiteKernel as W
|
|
64
|
+
from sklearn.exceptions import ConvergenceWarning
|
|
65
|
+
from scipy import optimize
|
|
66
|
+
from warnings import simplefilter
|
|
67
|
+
from numba import jit
|
|
68
|
+
import pprint
|
|
69
|
+
from ..Timeseries import pyaov
|
|
70
|
+
from bokeh.plotting import figure
|
|
71
|
+
|
|
72
|
+
pp = pprint.PrettyPrinter(width=130)
|
|
73
|
+
|
|
74
|
+
@jit(nopython=True)
|
|
75
|
+
def fourier_transform(nout, fmin, fmax, times, mags):
|
|
76
|
+
"""
|
|
77
|
+
Purpose
|
|
78
|
+
To compute the Fourier transform (power curve) of a set of data.
|
|
79
|
+
|
|
80
|
+
Based on algorithm - https://ui.adsabs.harvard.edu/abs/1975Ap%26SS..36..137D/abstract
|
|
81
|
+
Parameters
|
|
82
|
+
|
|
83
|
+
nout: int Number of frequency bins in output
|
|
84
|
+
fmin : float The minimum frequency of the frequency bins ( the frequency
|
|
85
|
+
unit is the inverse of the unit of time)
|
|
86
|
+
fmax : float The maximum frequency of the frequency bins ( the frequency
|
|
87
|
+
unit is the inverse of the unit of time)
|
|
88
|
+
times: np.ndarray of float values of time variable
|
|
89
|
+
mags: np.ndarray of float values of magnitude variable
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
A list of 4 objects:-
|
|
93
|
+
freqs np.ndarray of float value of frequency for each bin
|
|
94
|
+
periods np.ndarray of float value of period for each bin (in same unit as times)
|
|
95
|
+
FF np.ndarray of float amplitude squared for each bin
|
|
96
|
+
GG np.ndarray of powers normalized amplitude squared for each bin
|
|
97
|
+
History
|
|
98
|
+
11/2/20 Keith Inight. Initial version
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
ndata = len(times)
|
|
102
|
+
fr = np.zeros(nout)
|
|
103
|
+
fi = np.zeros(nout)
|
|
104
|
+
D = np.zeros(nout)
|
|
105
|
+
G = np.zeros(nout)
|
|
106
|
+
FF = np.zeros(nout)
|
|
107
|
+
GG = np.zeros(nout)
|
|
108
|
+
freqs = np.linspace(fmin, fmax, nout)
|
|
109
|
+
periods = 1/freqs
|
|
110
|
+
angular_freqs = (2*np.pi*freqs)
|
|
111
|
+
for k in range(nout):
|
|
112
|
+
for i in range(ndata):
|
|
113
|
+
A = angular_freqs[k]*times[i]
|
|
114
|
+
c = np.cos(A)
|
|
115
|
+
s = np.sin(A)
|
|
116
|
+
fr[k] += mags[i]*c
|
|
117
|
+
fi[k] += mags[i]*s
|
|
118
|
+
D[k] += c
|
|
119
|
+
G[k] += s
|
|
120
|
+
FF[k] = (fr[k]*fr[k]+fi[k]*fi[k])/(ndata**2)
|
|
121
|
+
GG[k] = (D[k]*D[k]+G[k]*G[k])/(ndata**2)
|
|
122
|
+
return [freqs, periods, FF, GG]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class Window3(QDialog):
|
|
126
|
+
def __init__(self, parent=None, ts_detrended=[]):
|
|
127
|
+
|
|
128
|
+
super(Window3, self).__init__(parent)
|
|
129
|
+
self.ts_detrended = ts_detrended
|
|
130
|
+
self.fpeak = self.ts_detrended.meta['fpeak']
|
|
131
|
+
self.fpeak_err = self.ts_detrended.meta['fpeak_err']
|
|
132
|
+
self.setWindowTitle("{} ".format(
|
|
133
|
+
self.ts_detrended.meta['object_name']))
|
|
134
|
+
# a figure instance to plot on
|
|
135
|
+
self.figure = plt.figure(dpi=80)
|
|
136
|
+
self.setGeometry(200, 200, 1000, 600)
|
|
137
|
+
# this is the Canvas Widget that displays the `figure`
|
|
138
|
+
# it takes the `figure` instance as a parameter to __init__
|
|
139
|
+
|
|
140
|
+
self.canvas3 = FigureCanvas(self.figure)
|
|
141
|
+
|
|
142
|
+
self.toolbar3 = NavigationToolbar(self.canvas3, self)
|
|
143
|
+
|
|
144
|
+
period_fold = 1/self.fpeak
|
|
145
|
+
|
|
146
|
+
self.phase = self.ts_detrended.time.value/period_fold - \
|
|
147
|
+
(self.ts_detrended.time.value/period_fold).astype('int')
|
|
148
|
+
if len(self.ts_detrended['y3']) > 50:
|
|
149
|
+
bins = 30
|
|
150
|
+
else:
|
|
151
|
+
bins = 10
|
|
152
|
+
np.linspace(0, 1-1/bins, num=bins)
|
|
153
|
+
self.bin_phase = []
|
|
154
|
+
self.bin_y = []
|
|
155
|
+
self.bin_y_err = []
|
|
156
|
+
for bphase in np.linspace(0, 1-1/bins, num=bins):
|
|
157
|
+
mask = (self.phase < bphase+1/bins) & (self.phase >= bphase)
|
|
158
|
+
if len(self.ts_detrended['y3'][mask]) > 0:
|
|
159
|
+
self.bin_phase += [bphase+0.5/bins]
|
|
160
|
+
baverage, norm = np.average(self.ts_detrended['y3'][mask].value, weights=(
|
|
161
|
+
1/self.ts_detrended['y_err'][mask].value)**2, returned=True)
|
|
162
|
+
self.bin_y += [baverage]
|
|
163
|
+
self.bin_y_err += [1/np.sqrt(norm)]
|
|
164
|
+
self.plot()
|
|
165
|
+
|
|
166
|
+
# set the layout
|
|
167
|
+
layout3 = QVBoxLayout()
|
|
168
|
+
layout3.addWidget(self.toolbar3)
|
|
169
|
+
layout3.addWidget(self.canvas3)
|
|
170
|
+
self.setLayout(layout3)
|
|
171
|
+
|
|
172
|
+
def closeEvent(self, event):
|
|
173
|
+
plt.close()
|
|
174
|
+
super(Window3, self).closeEvent(event)
|
|
175
|
+
|
|
176
|
+
def plot(self):
|
|
177
|
+
self.figure.clear()
|
|
178
|
+
gs = gridspec.GridSpec(2, 2, height_ratios=[4, 1])
|
|
179
|
+
y3 = self.ts_detrended['y3'].value
|
|
180
|
+
err = self.ts_detrended['y_err'].value
|
|
181
|
+
|
|
182
|
+
# create an axis
|
|
183
|
+
ax = plt.subplot(gs[0, 0])
|
|
184
|
+
# plot data
|
|
185
|
+
ax.errorbar(np.concatenate((self.phase, self.phase+1)),
|
|
186
|
+
np.concatenate((y3, y3)), yerr=np.concatenate((err, err)), fmt='.', ecolor='grey', elinewidth=.3)
|
|
187
|
+
|
|
188
|
+
ax.set_title('f = {:.6f}'.format(self.fpeak)+' d$^{-1}$' +
|
|
189
|
+
' P={:.6f} $\pm$ {:.8f}'.format(24/self.fpeak, 24*self.fpeak_err/((self.fpeak)**2)) +
|
|
190
|
+
' h ({:.6f} $\pm$ {:.10f} days)'.format(1/self.fpeak, self.fpeak_err/(self.fpeak**2)))
|
|
191
|
+
|
|
192
|
+
ax.set_xlabel('Phase')
|
|
193
|
+
ax.set_ylabel(str(self.ts_detrended['y3'].unit))
|
|
194
|
+
ymin, ymax = ax.get_ylim()
|
|
195
|
+
ax.set_ylim(ymax, ymin)
|
|
196
|
+
# refresh canvas
|
|
197
|
+
ax1 = plt.subplot(gs[0, 1])
|
|
198
|
+
bp = np.array(self.bin_phase)
|
|
199
|
+
ax1.errorbar(np.concatenate([bp, bp+1]),
|
|
200
|
+
self.bin_y + self.bin_y,
|
|
201
|
+
self.bin_y_err + self.bin_y_err, fmt='.', ecolor='grey', elinewidth=.3)
|
|
202
|
+
|
|
203
|
+
ymin, ymax = ax1.get_ylim()
|
|
204
|
+
ax1.set_ylim(ymax, ymin)
|
|
205
|
+
ax1.set_title('Binned plot')
|
|
206
|
+
ax1.set_xlabel('Phase')
|
|
207
|
+
ax2 = plt.subplot(gs[1, 0:2])
|
|
208
|
+
ax2.text(0, 0.95, pp.pformat({i: self.ts_detrended.meta[i] for i in self.ts_detrended.meta if i in
|
|
209
|
+
['frange', 'crop', 'prewhiten', 'trend', 'Gaussian_Process_regression', 'method','peak_type', 'nh2', 'fpeak']}), va='top')
|
|
210
|
+
ax2.axis('off')
|
|
211
|
+
|
|
212
|
+
self.canvas3.draw()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class Window2(QDialog):
|
|
216
|
+
def __init__(self, parent=None, ts_detrended=None):
|
|
217
|
+
|
|
218
|
+
super(Window2, self).__init__(parent)
|
|
219
|
+
|
|
220
|
+
self.ts_detrended = ts_detrended
|
|
221
|
+
self.setWindowTitle("{} ".format(ts_detrended.meta['object_name']))
|
|
222
|
+
# a figure instance to plot on
|
|
223
|
+
self.figure = plt.figure(dpi=80)
|
|
224
|
+
self.setGeometry(150, 150, 800, 400)
|
|
225
|
+
# this is the Canvas Widget that displays the `figure`
|
|
226
|
+
# it takes the `figure` instance as a parameter to __init__
|
|
227
|
+
self.canvas1 = FigureCanvas(self.figure)
|
|
228
|
+
# this is the Navigation widget
|
|
229
|
+
# it takes the Canvas widget and a parent
|
|
230
|
+
self.toolbar1 = NavigationToolbar(self.canvas1, self)
|
|
231
|
+
self.times = self.ts_detrended.time.value-self.ts_detrended.time.value.min()
|
|
232
|
+
self.y = self.ts_detrended['y3'].value
|
|
233
|
+
self.y_err = self.ts_detrended['y_err'].value
|
|
234
|
+
method = self.ts_detrended.meta['method']
|
|
235
|
+
self.nh2 = self.ts_detrended.meta['nh2']
|
|
236
|
+
self.binsize = self.ts_detrended.meta['binsize']
|
|
237
|
+
|
|
238
|
+
fmin, fmax, fbins = self.ts_detrended.meta['frange'][-1]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
if method == "amhw":
|
|
242
|
+
self.per, self.freq, self.fpeak = pyaov.amhw(
|
|
243
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin, nh2=self.nh2)
|
|
244
|
+
|
|
245
|
+
elif method == "pspw":
|
|
246
|
+
|
|
247
|
+
self.per, self.freq, self.fpeak = pyaov.pspw(
|
|
248
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin)
|
|
249
|
+
|
|
250
|
+
elif method == "atrw":
|
|
251
|
+
|
|
252
|
+
self.per, self.freq, self.fpeak = pyaov.atrw(
|
|
253
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin, nh2=self.nh2)
|
|
254
|
+
|
|
255
|
+
elif method == "aovw":
|
|
256
|
+
|
|
257
|
+
self.per, self.freq, self.fpeak = pyaov.aovw(
|
|
258
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin, nh2=self.nh2)
|
|
259
|
+
|
|
260
|
+
elif method == "f_mw":
|
|
261
|
+
|
|
262
|
+
self.per, self.freq, self.fpeak = pyaov.f_mw(
|
|
263
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin)
|
|
264
|
+
|
|
265
|
+
elif method == "lomw":
|
|
266
|
+
|
|
267
|
+
self.per, self.freq, self.fpeak = pyaov.lomw(
|
|
268
|
+
self.times, self.y, self.y_err, fmax, (fmax-fmin)/fbins, fr0=fmin)
|
|
269
|
+
|
|
270
|
+
else:
|
|
271
|
+
print("Invalid method ", method)
|
|
272
|
+
raise ValueError("Invalid method "+str(method))
|
|
273
|
+
|
|
274
|
+
self.plot(self.freq, self.per, title=method)
|
|
275
|
+
|
|
276
|
+
self.Fold_button = QPushButton("Fold")
|
|
277
|
+
self.Fold_button.clicked.connect(self.Phase_fold)
|
|
278
|
+
|
|
279
|
+
self.Fold_half_button = QPushButton("Fold "+"\u00BD"+"f")
|
|
280
|
+
self.Fold_half_button.clicked.connect(self.Phase_fold_half)
|
|
281
|
+
|
|
282
|
+
self.Recalculate_button = QPushButton("Recalculate")
|
|
283
|
+
self.Recalculate_button.clicked.connect(self.Recalculate)
|
|
284
|
+
|
|
285
|
+
self.Prewhiten_button = QPushButton("Prewhiten")
|
|
286
|
+
self.Prewhiten_button.clicked.connect(self.Prewhiten)
|
|
287
|
+
|
|
288
|
+
self.row_layout = QHBoxLayout()
|
|
289
|
+
self.row_layout.addWidget(self.toolbar1)
|
|
290
|
+
self.row_layout.addWidget(self.Fold_button)
|
|
291
|
+
self.row_layout.addWidget(self.Fold_half_button)
|
|
292
|
+
self.row_layout.addWidget(self.Recalculate_button)
|
|
293
|
+
self.row_layout.addWidget(self.Prewhiten_button)
|
|
294
|
+
# set the layout
|
|
295
|
+
layout1 = QVBoxLayout()
|
|
296
|
+
layout1.addLayout(self.row_layout)
|
|
297
|
+
layout1.addWidget(self.canvas1)
|
|
298
|
+
self.setLayout(layout1)
|
|
299
|
+
|
|
300
|
+
def closeEvent(self, event):
|
|
301
|
+
|
|
302
|
+
plt.close()
|
|
303
|
+
super(Window2, self).closeEvent(event)
|
|
304
|
+
|
|
305
|
+
def Phase_fold(self):
|
|
306
|
+
def sine_fit(x, a, b, c):
|
|
307
|
+
return a * np.sin(b * x+c)
|
|
308
|
+
axes = self.canvas1.figure.axes[0]
|
|
309
|
+
freq_lo, freq_hi = axes.get_xlim()
|
|
310
|
+
|
|
311
|
+
mask = (self.freq > freq_lo) & (self.freq < freq_hi)
|
|
312
|
+
if (self.fpeak > freq_lo) & (self.fpeak< freq_hi):
|
|
313
|
+
self.ts_detrended.meta['fpeak']=self.fpeak
|
|
314
|
+
else:
|
|
315
|
+
self.ts_detrended.meta['fpeak'] = self.freq[mask][self.per[mask].argmax()] # seed value
|
|
316
|
+
if self.ts_detrended.meta['peak_type']=='Parabola':
|
|
317
|
+
xm, fm, dx = pyaov.peak(self.per[mask])
|
|
318
|
+
|
|
319
|
+
self.ts_detrended.meta['fpeak'] = self.freq[mask][0]+xm*self.binsize
|
|
320
|
+
self.ts_detrended.meta['fpeak_err'] = dx*self.binsize
|
|
321
|
+
else:
|
|
322
|
+
print("OTHER")
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
print("fpeak",self.ts_detrended.meta['fpeak'])
|
|
326
|
+
self.params, self.params_covariance = optimize.curve_fit(sine_fit, self.ts_detrended.time.value, self.ts_detrended['y3'].value,
|
|
327
|
+
p0=[1, 2*np.pi*self.ts_detrended.meta['fpeak'], 0])
|
|
328
|
+
print(self.params)
|
|
329
|
+
print(self.params_covariance)
|
|
330
|
+
except:
|
|
331
|
+
print('failed')
|
|
332
|
+
self.params = np.array([0, 2*np.pi*self.ts_detrended.meta['fpeak'], 0])
|
|
333
|
+
self.params_covariance = np.array(
|
|
334
|
+
[[0, 0, 0], [0, 0, 0], [0, 0, 0]])
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
self.ts_detrended.meta['fpeak'] = self.params[1]/(2*np.pi)
|
|
338
|
+
self.ts_detrended.meta['fpeak_err'] = np.sqrt(self.params_covariance[1,1])/(2*np.pi)
|
|
339
|
+
print("output",self.ts_detrended.meta['fpeak'])
|
|
340
|
+
|
|
341
|
+
main3 = Window3(self, ts_detrended=self.ts_detrended)
|
|
342
|
+
main3.show()
|
|
343
|
+
|
|
344
|
+
def Phase_fold_half(self):
|
|
345
|
+
|
|
346
|
+
axes = self.canvas1.figure.axes[0]
|
|
347
|
+
freq_lo, freq_hi = axes.get_xlim()
|
|
348
|
+
mask = (self.freq > freq_lo) & (self.freq < freq_hi)
|
|
349
|
+
xm, fm, dx = pyaov.peak(self.per[mask])
|
|
350
|
+
self.ts_detrended.meta['fpeak'] = (
|
|
351
|
+
self.freq[mask][0]+xm*self.binsize)*0.5
|
|
352
|
+
self.ts_detrended.meta['fpeak_err'] = dx*self.binsize
|
|
353
|
+
main3 = Window3(self, ts_detrended=self.ts_detrended)
|
|
354
|
+
main3.show()
|
|
355
|
+
|
|
356
|
+
def Recalculate(self):
|
|
357
|
+
|
|
358
|
+
axes = self.canvas1.figure.axes[0]
|
|
359
|
+
freq_lo, freq_hi = axes.get_xlim()
|
|
360
|
+
fbins = self.ts_detrended.meta['frange'][-1][2]
|
|
361
|
+
|
|
362
|
+
self.ts_detrended.meta['frange'] += [[freq_lo, freq_hi, fbins]]
|
|
363
|
+
|
|
364
|
+
self.ts_detrended.meta['binsize'] = (freq_hi -
|
|
365
|
+
freq_lo)/fbins
|
|
366
|
+
|
|
367
|
+
main2a = Window2(self, ts_detrended=self.ts_detrended)
|
|
368
|
+
main2a.show()
|
|
369
|
+
|
|
370
|
+
def Prewhiten(self):
|
|
371
|
+
axes = self.canvas1.figure.axes[0]
|
|
372
|
+
freq_lo, freq_hi = axes.get_xlim()
|
|
373
|
+
per_lo, per_hi = axes.get_ylim()
|
|
374
|
+
mask = (self.freq > freq_lo) & (self.freq < freq_hi) & (
|
|
375
|
+
self.per > per_lo) & (self.per < per_hi)
|
|
376
|
+
|
|
377
|
+
xm, fm, dx = pyaov.peak(self.per[mask])
|
|
378
|
+
|
|
379
|
+
foundfreq = self.freq[mask][0]+xm*self.binsize
|
|
380
|
+
# already got this frequency in the list
|
|
381
|
+
|
|
382
|
+
frout,dfrout,valout=pyaov.prew(self.times, self.y, self.y_err, foundfreq, nh2=11)
|
|
383
|
+
print('frout={} dfrout={}'.format(frout,dfrout))
|
|
384
|
+
|
|
385
|
+
if frout in self.ts_detrended.meta['prewhiten']:
|
|
386
|
+
return
|
|
387
|
+
|
|
388
|
+
self.ts_detrended.meta['fpeak'] =frout
|
|
389
|
+
|
|
390
|
+
self.ts_prewhite = self.ts_detrended
|
|
391
|
+
|
|
392
|
+
self.ts_prewhite.meta['prewhiten'] += [foundfreq]
|
|
393
|
+
print(self.ts_prewhite.meta['prewhiten'])
|
|
394
|
+
|
|
395
|
+
self.ts_prewhite['y3'] = valout*self.ts_detrended['y3'].unit
|
|
396
|
+
|
|
397
|
+
self.ts_prewhite.meta['frange'] = [self.ts_detrended.meta['frange'][0]]
|
|
398
|
+
main2b = Window2(self, ts_detrended=self.ts_prewhite)
|
|
399
|
+
main2b.show()
|
|
400
|
+
|
|
401
|
+
def plot(self, freq, per, title=''):
|
|
402
|
+
|
|
403
|
+
self.figure.clear()
|
|
404
|
+
|
|
405
|
+
# create an axis
|
|
406
|
+
ax = self.figure.add_subplot(111)
|
|
407
|
+
# plot data
|
|
408
|
+
ax.plot(freq, per, '-', linewidth=0.5)
|
|
409
|
+
ax.set_xlabel('Frequency(1/D)')
|
|
410
|
+
ax.set_ylabel('Power')
|
|
411
|
+
ax.set_title(title)
|
|
412
|
+
# refresh canvas
|
|
413
|
+
self.canvas1.draw()
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class Window1(QDialog):
|
|
417
|
+
def __init__(self, parent=None, ts_cropped=None):
|
|
418
|
+
super(Window1, self).__init__(parent)
|
|
419
|
+
self.ts_cropped = ts_cropped
|
|
420
|
+
self.setWindowTitle("{} ".format(
|
|
421
|
+
str(self.ts_cropped.meta['object_name'])))
|
|
422
|
+
# a figure instance to plot on
|
|
423
|
+
# self.ts_cropped.sort('time')
|
|
424
|
+
|
|
425
|
+
self.figure = plt.figure(dpi=80)
|
|
426
|
+
self.setGeometry(100, 100, 1000, 400)
|
|
427
|
+
# this is the Canvas Widget that displays the `figure`
|
|
428
|
+
# it takes the `figure` instance as a parameter to __init__
|
|
429
|
+
self.canvas = FigureCanvas(self.figure)
|
|
430
|
+
|
|
431
|
+
# this is the Navigation widget
|
|
432
|
+
# it takes the Canvas widget and a parent
|
|
433
|
+
|
|
434
|
+
#self.toolbar = NavigationToolbar(self.canvas, self)
|
|
435
|
+
|
|
436
|
+
self.label1 = QLabel("Trend")
|
|
437
|
+
self.label1.alignment()
|
|
438
|
+
self.label1.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
439
|
+
|
|
440
|
+
self.trendbox = QSpinBox()
|
|
441
|
+
self.trendbox.setGeometry(0, 0, 30, 20)
|
|
442
|
+
self.trendbox.setValue(0)
|
|
443
|
+
self.trendbox.setMinimum(0)
|
|
444
|
+
self.trendbox.valueChanged.connect(self.redraw)
|
|
445
|
+
# -------------------------
|
|
446
|
+
self.label2 = QLabel("Boxcar")
|
|
447
|
+
self.label2.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
448
|
+
self.label2.setToolTip("This sets the length of the boxcar")
|
|
449
|
+
|
|
450
|
+
self.boxcarbox = QSpinBox()
|
|
451
|
+
self.boxcarbox.setGeometry(0, 0, 30, 20)
|
|
452
|
+
self.boxcarbox.setValue(1)
|
|
453
|
+
self.boxcarbox.setMinimum(1)
|
|
454
|
+
self.boxcarbox.setSingleStep(2)
|
|
455
|
+
self.boxcarbox.valueChanged.connect(self.redraw)
|
|
456
|
+
|
|
457
|
+
# -------------------------
|
|
458
|
+
self.Gaussian_Process_Regression = QCheckBox(
|
|
459
|
+
"Gaussian Process Regression")
|
|
460
|
+
self.Gaussian_Process_Regression.setLayoutDirection(Qt.RightToLeft)
|
|
461
|
+
self.Gaussian_Process_Regression.stateChanged.connect(self.redraw)
|
|
462
|
+
# -------------------------
|
|
463
|
+
|
|
464
|
+
self.label3 = QLabel("nh")
|
|
465
|
+
self.label3.alignment()
|
|
466
|
+
self.label3.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
467
|
+
|
|
468
|
+
self.nhbox = QSpinBox()
|
|
469
|
+
self.nhbox.setGeometry(0, 0, 30, 20)
|
|
470
|
+
self.nhbox.setValue(2)
|
|
471
|
+
self.nhbox.setMinimum(2)
|
|
472
|
+
|
|
473
|
+
# -------------------------
|
|
474
|
+
self.row_layout = QHBoxLayout()
|
|
475
|
+
self.row_layout.addWidget(self.label1)
|
|
476
|
+
self.row_layout.addWidget(self.trendbox)
|
|
477
|
+
self.row_layout.addWidget(self.label2)
|
|
478
|
+
self.row_layout.addWidget(self.boxcarbox)
|
|
479
|
+
self.row_layout.addWidget(self.Gaussian_Process_Regression)
|
|
480
|
+
self.row_layout.addWidget(self.label3)
|
|
481
|
+
self.row_layout.addWidget(self.nhbox)
|
|
482
|
+
|
|
483
|
+
self.fpeaktype=QButtonGroup()
|
|
484
|
+
self.fpeaktype.setExclusive(True)
|
|
485
|
+
|
|
486
|
+
self.radio = QRadioButton("Parabola")
|
|
487
|
+
self.fpeaktype.addButton(self.radio, 0)
|
|
488
|
+
self.radio.setChecked(True)
|
|
489
|
+
self.radio.setLayoutDirection(Qt.RightToLeft)
|
|
490
|
+
self.row_layout.addWidget(self.radio)
|
|
491
|
+
self.row_layout.setAlignment(self.radio, Qt.AlignVCenter)
|
|
492
|
+
self.radio = QRadioButton("Sine")
|
|
493
|
+
self.fpeaktype.addButton(self.radio, 1)
|
|
494
|
+
self.radio.setChecked(False)
|
|
495
|
+
self.radio.setLayoutDirection(Qt.RightToLeft)
|
|
496
|
+
self.row_layout.addWidget(self.radio)
|
|
497
|
+
self.row_layout.setAlignment(self.radio, Qt.AlignVCenter)
|
|
498
|
+
|
|
499
|
+
#self.fpeaktype.buttonClicked.connect(self.on_draw_per)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
# Define the second row of widgets
|
|
504
|
+
|
|
505
|
+
# self.nhbox.valueChanged.connect(self.nh2)
|
|
506
|
+
# self.nh2=2
|
|
507
|
+
|
|
508
|
+
self.listOfChoices = ["amhw", "pspw", "atrw",
|
|
509
|
+
"aovw", "f_mw", "lomw"]
|
|
510
|
+
self.choice_tooltips = {"amhw": "Returns multiharmonic AOV periodogram,\n"
|
|
511
|
+
"obtained by fitting data with a series of trigonometric polynomials.\n"
|
|
512
|
+
"For default nh2=3 this is Lomb-Scargle periodogram\n"
|
|
513
|
+
"corrected for constant shift",
|
|
514
|
+
"pspw": "Returns Power Spectrum. Principal use for calculation of window function.\n"
|
|
515
|
+
"For periodogram we recommend amhv routine with nh2=2 instead",
|
|
516
|
+
"atrw": "Returns AOV periodogram for search of transits/eclipses.\n"
|
|
517
|
+
"For this purpose data are fitted with a box-like \n"
|
|
518
|
+
"(inverted top-hat) function",
|
|
519
|
+
"aovw": "Analysis of variance taking account of weights\n"
|
|
520
|
+
"i.e. observastional errors",
|
|
521
|
+
"f_mw": "Returns generalized Lomb-Scargle periodogram\n"
|
|
522
|
+
"of data, using the original Ferraz-Mello (1981) algorithm.",
|
|
523
|
+
"lomw": "Returns AOV periodogram, obtained by phase-folding and binning of data."}
|
|
524
|
+
self.row2_layout = QHBoxLayout()
|
|
525
|
+
|
|
526
|
+
self.radioGroup = QButtonGroup()
|
|
527
|
+
self.radioGroup.setExclusive(True)
|
|
528
|
+
|
|
529
|
+
for i, row in enumerate(self.listOfChoices):
|
|
530
|
+
self.radio = QRadioButton(row)
|
|
531
|
+
self.radio.setToolTip(self.choice_tooltips[row])
|
|
532
|
+
self.radioGroup.addButton(self.radio, i)
|
|
533
|
+
# if i==0:
|
|
534
|
+
# self.radio.setChecked(True)
|
|
535
|
+
|
|
536
|
+
self.row2_layout.addWidget(self.radio)
|
|
537
|
+
self.row2_layout.setAlignment(self.radio, Qt.AlignVCenter)
|
|
538
|
+
self.radioGroup.buttonClicked.connect(self.on_draw_per)
|
|
539
|
+
|
|
540
|
+
# set the top level layout
|
|
541
|
+
layout = QVBoxLayout()
|
|
542
|
+
layout.addLayout(self.row_layout)
|
|
543
|
+
layout.addLayout(self.row2_layout)
|
|
544
|
+
layout.addWidget(self.canvas)
|
|
545
|
+
|
|
546
|
+
self.setLayout(layout)
|
|
547
|
+
self.plot()
|
|
548
|
+
simplefilter('ignore', category=ConvergenceWarning)
|
|
549
|
+
|
|
550
|
+
def on_draw_per(self, meth):
|
|
551
|
+
print(self.fpeaktype.checkedButton().text())
|
|
552
|
+
self.ts_cropped.meta['peak_type']=self.fpeaktype.checkedButton().text()
|
|
553
|
+
self.ts_cropped.meta['method'] = meth.text()
|
|
554
|
+
main2 = Window2(self, ts_detrended=self.get_detrended_subset())
|
|
555
|
+
main2.show()
|
|
556
|
+
|
|
557
|
+
def closeEvent(self, event):
|
|
558
|
+
|
|
559
|
+
plt.close()
|
|
560
|
+
super(Window1, self).closeEvent(event)
|
|
561
|
+
|
|
562
|
+
def get_detrended_subset(self):
|
|
563
|
+
# calculate best fit trend line
|
|
564
|
+
global dummy
|
|
565
|
+
self.ts_detrended = self.ts_cropped.copy()
|
|
566
|
+
|
|
567
|
+
self.ts_cropped.meta['trend'] = self.trendbox.value()
|
|
568
|
+
self.ts_cropped.meta['boxcar'] = self.boxcarbox.value()
|
|
569
|
+
self.ts_cropped.meta['nh2'] = self.nhbox.value()
|
|
570
|
+
self.ts_cropped.meta['Gaussian_Process_Regression'] = self.Gaussian_Process_Regression.isChecked(
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
c = Chebyshev.fit(self.ts_detrended.time.value,
|
|
574
|
+
self.ts_detrended['y'].value, deg=self.trendbox.value())
|
|
575
|
+
self.ts_detrended['y1'] = self.ts_detrended['y'] - \
|
|
576
|
+
c(self.ts_detrended.time.value)*self.ts_detrended['y'].unit
|
|
577
|
+
|
|
578
|
+
if self.boxcarbox.value() > 1:
|
|
579
|
+
box_kernel = Box1DKernel(self.boxcarbox.value())
|
|
580
|
+
smoothed = convolve(self.ts_detrended['y1'].value, box_kernel)
|
|
581
|
+
self.ts_detrended['y2'] = self.ts_detrended['y1'] - \
|
|
582
|
+
smoothed*self.ts_detrended['y1'].unit
|
|
583
|
+
for i in range(int(self.boxcarbox.value()/2)):
|
|
584
|
+
self.ts_detrended['y2'][i] = 0
|
|
585
|
+
self.ts_detrended['y2'][len(self.ts_detrended['y2'])-1-i] = 0
|
|
586
|
+
else:
|
|
587
|
+
self.ts_detrended['y2'] = self.ts_detrended['y1']
|
|
588
|
+
|
|
589
|
+
# self.ts_detrended.sort('time')
|
|
590
|
+
|
|
591
|
+
if self.Gaussian_Process_Regression.isChecked():
|
|
592
|
+
kernel = C(1.0, (1e-3, 1e3)) * RBF(10, (1, 1e2)) + \
|
|
593
|
+
W(noise_level=1e-3, noise_level_bounds=(1e-06, 1))
|
|
594
|
+
gp = GaussianProcessRegressor(
|
|
595
|
+
kernel=kernel, alpha=self.ts_cropped['y_err'].value ** 2, n_restarts_optimizer=3)
|
|
596
|
+
time2d = np.atleast_2d(self.ts_detrended.time.value).T
|
|
597
|
+
gp.fit(time2d, self.ts_detrended['y2'].value)
|
|
598
|
+
mag_pred, sigma_mag_pred = gp.predict(time2d, return_std=True)
|
|
599
|
+
self.ts_detrended['y3'] = self.ts_detrended['y2'] - \
|
|
600
|
+
mag_pred * self.ts_detrended['y2'].unit
|
|
601
|
+
else:
|
|
602
|
+
self.ts_detrended['y3'] = self.ts_detrended['y2']
|
|
603
|
+
return self.ts_detrended
|
|
604
|
+
|
|
605
|
+
def Fourier(self):
|
|
606
|
+
self.ts_cropped.meta['method'] = 'Fourier'
|
|
607
|
+
main2 = Window2(self, ts_detrended=self.get_detrended_subset())
|
|
608
|
+
main2.show()
|
|
609
|
+
|
|
610
|
+
def redraw(self):
|
|
611
|
+
# Update display to include the updated trend/boxcar parameters to be
|
|
612
|
+
# displayed
|
|
613
|
+
self.plot()
|
|
614
|
+
|
|
615
|
+
def plot(self):
|
|
616
|
+
|
|
617
|
+
self.ts_detrended = self.get_detrended_subset()
|
|
618
|
+
|
|
619
|
+
xdata = self.ts_cropped.time.value
|
|
620
|
+
# calculate the "trend" that has been used
|
|
621
|
+
ydata = self.ts_detrended['y']-self.ts_detrended['y3']
|
|
622
|
+
|
|
623
|
+
self.figure.clear()
|
|
624
|
+
# create an axis
|
|
625
|
+
ax = self.figure.add_subplot(111)
|
|
626
|
+
# plot data
|
|
627
|
+
ax.errorbar(self.ts_cropped.time.value,
|
|
628
|
+
self.ts_cropped['y'].value, yerr=self.ts_cropped['y_err'].value, fmt='.', color='magenta')
|
|
629
|
+
ax.plot(xdata, ydata, '-k')
|
|
630
|
+
ymin, ymax = ax.get_ylim()
|
|
631
|
+
ax.set_ylim(ymax, ymin)
|
|
632
|
+
|
|
633
|
+
ax.set_xlabel('MJD')
|
|
634
|
+
ax.set_ylabel('Magnitude')
|
|
635
|
+
ax.set_title(str(self.ts_cropped.meta['object_name']))
|
|
636
|
+
# refresh canvas
|
|
637
|
+
|
|
638
|
+
self.canvas.draw()
|
|
639
|
+
|
|
640
|
+
class Window(QDialog):
|
|
641
|
+
def __init__(self, ts, parent=None):
|
|
642
|
+
super(Window, self).__init__(parent)
|
|
643
|
+
self.ts = ts
|
|
644
|
+
self.setWindowTitle("{} ".format(str(self.ts.meta['object_name'])))
|
|
645
|
+
# a figure instance to plot on
|
|
646
|
+
|
|
647
|
+
self.figure = plt.figure(dpi=80)
|
|
648
|
+
self.setGeometry(50, 50, 1000, 400)
|
|
649
|
+
# this is the Canvas Widget that displays the `figure`
|
|
650
|
+
# it takes the `figure` instance as a parameter to __init__
|
|
651
|
+
self.canvas = FigureCanvas(self.figure)
|
|
652
|
+
# this is the Navigation widget
|
|
653
|
+
# it takes the Canvas widget and a parent
|
|
654
|
+
self.toolbar = NavigationToolbar(self.canvas, self)
|
|
655
|
+
|
|
656
|
+
self.analyse_button = QPushButton("Analyse")
|
|
657
|
+
self.analyse_button.clicked.connect(self.Analyse)
|
|
658
|
+
|
|
659
|
+
self.row_layout = QHBoxLayout()
|
|
660
|
+
self.row_layout.addWidget(self.toolbar)
|
|
661
|
+
self.row_layout.addWidget(self.analyse_button)
|
|
662
|
+
|
|
663
|
+
# set the top level layout
|
|
664
|
+
layout = QVBoxLayout()
|
|
665
|
+
layout.addLayout(self.row_layout)
|
|
666
|
+
layout.addWidget(self.canvas)
|
|
667
|
+
|
|
668
|
+
self.setLayout(layout)
|
|
669
|
+
self.plot()
|
|
670
|
+
|
|
671
|
+
def closeEvent(self, event):
|
|
672
|
+
|
|
673
|
+
plt.close()
|
|
674
|
+
super(Window, self).closeEvent(event)
|
|
675
|
+
|
|
676
|
+
def get_subset(self):
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
axes = self.canvas.figure.axes[0]
|
|
680
|
+
mjd1, mjd2 = axes.get_xlim()
|
|
681
|
+
y_hi, y_lo = axes.get_ylim()
|
|
682
|
+
mask = (self.ts.time.value > mjd1) &\
|
|
683
|
+
(self.ts.time.value < mjd2) &\
|
|
684
|
+
(self.ts['y'].value > y_lo) &\
|
|
685
|
+
(self.ts['y'].value < y_hi)
|
|
686
|
+
self.new_ts = self.ts.copy()[mask]
|
|
687
|
+
self.new_ts.meta['crop'] = [mjd1, mjd2, y_lo, y_hi]
|
|
688
|
+
except:
|
|
689
|
+
self.new_ts = self.ts.copy()
|
|
690
|
+
return self.new_ts
|
|
691
|
+
|
|
692
|
+
def Analyse(self):
|
|
693
|
+
|
|
694
|
+
main1 = Window1(self, self.get_subset())
|
|
695
|
+
main1.show()
|
|
696
|
+
|
|
697
|
+
def redraw(self):
|
|
698
|
+
# Update display to include the updated trend/boxcar parameters to be
|
|
699
|
+
# displayed
|
|
700
|
+
self.plot()
|
|
701
|
+
|
|
702
|
+
def plot(self):
|
|
703
|
+
self.figure.clear()
|
|
704
|
+
|
|
705
|
+
# create an axis
|
|
706
|
+
ax = self.figure.add_subplot(111)
|
|
707
|
+
# plot data
|
|
708
|
+
ax.errorbar(self.ts.time.value, self.ts['y'].value,
|
|
709
|
+
yerr=self.ts['y_err'].value, fmt='.', color='magenta')
|
|
710
|
+
ymin, ymax = ax.get_ylim()
|
|
711
|
+
ax.set_ylim(ymax, ymin)
|
|
712
|
+
ax.set_xlabel(str(self.ts.time.format))
|
|
713
|
+
ax.set_ylabel(str(self.ts['y'].unit))
|
|
714
|
+
ax.set_title(str(self.ts.meta['object_name']))
|
|
715
|
+
# refresh canvas
|
|
716
|
+
self.canvas.draw()
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def display_light_curve(original_ts):
|
|
720
|
+
"""
|
|
721
|
+
Parameters
|
|
722
|
+
----------
|
|
723
|
+
original_ts : Timeseries object
|
|
724
|
+
This is a standard astropy time series object with (dimensioned) parameters
|
|
725
|
+
time,y and y_err. In addition it includes a metadata dictionary (meta) with
|
|
726
|
+
parameters
|
|
727
|
+
'object path': path to folder where time series data is held
|
|
728
|
+
'object_name': name of object
|
|
729
|
+
'frange': list of lists. The lowest level list has three values applicable
|
|
730
|
+
to periodograms ; lowest frequency, highest frequency and number of bins
|
|
731
|
+
|
|
732
|
+
Returns
|
|
733
|
+
-------
|
|
734
|
+
None
|
|
735
|
+
"""
|
|
736
|
+
ts = original_ts.copy()
|
|
737
|
+
ts.sort('time')
|
|
738
|
+
if 'object_name' not in ts.meta:
|
|
739
|
+
ts.meta['object_name'] = ''
|
|
740
|
+
ts.meta['crop'] = []
|
|
741
|
+
if 'prewhiten' not in ts.meta:
|
|
742
|
+
ts.meta['prewhiten'] = []
|
|
743
|
+
if 'frange' not in ts.meta:
|
|
744
|
+
period_low = 0.5 # shortest period evaluated (hours)
|
|
745
|
+
period_hi = 30 # longest period evaluated
|
|
746
|
+
fmin = 24/period_hi
|
|
747
|
+
fmax = 24/period_low
|
|
748
|
+
fbins = 150000
|
|
749
|
+
ts.meta['frange'] = [[fmin, fmax, fbins]]
|
|
750
|
+
ts.meta['binsize'] = (ts.meta['frange'][0][1] -
|
|
751
|
+
ts.meta['frange'][0][0])/ts.meta['frange'][0][2]
|
|
752
|
+
|
|
753
|
+
# Cannot change order of these
|
|
754
|
+
app = QApplication(sys.argv)
|
|
755
|
+
main = Window(ts)
|
|
756
|
+
main.show()
|
|
757
|
+
app.exec_()
|
|
758
|
+
|
|
759
|
+
def getanalysis(data):
|
|
760
|
+
from astropy.time import Time
|
|
761
|
+
from astropy.timeseries import TimeSeries
|
|
762
|
+
from astropy.units import cds
|
|
763
|
+
from astropy import units as u
|
|
764
|
+
from astropy.io import ascii, fits
|
|
765
|
+
|
|
766
|
+
ts_filename='lightcurve_data.csv'
|
|
767
|
+
data.to_csv(ts_filename,index=False)
|
|
768
|
+
|
|
769
|
+
ts_path = os.path.join(os.getcwd(),ts_filename)
|
|
770
|
+
|
|
771
|
+
flux_unit=u.def_unit("Flux")
|
|
772
|
+
no_unit=u.def_unit("Unspecified")
|
|
773
|
+
|
|
774
|
+
'''
|
|
775
|
+
_, appname = os.path.split(sys.argv[0])
|
|
776
|
+
|
|
777
|
+
default_file = os.sep.join([str(Path.home()), 'KI app parameters', appname[:-3]+'.def'])
|
|
778
|
+
'''
|
|
779
|
+
|
|
780
|
+
data.sort_values('hjd',inplace=True)
|
|
781
|
+
xd=data['hjd']-2400000.5
|
|
782
|
+
|
|
783
|
+
yd=data['mag']
|
|
784
|
+
ed=data['magerr']
|
|
785
|
+
|
|
786
|
+
y_unit=u.mag
|
|
787
|
+
|
|
788
|
+
filters = list(set(data['filtercode']))
|
|
789
|
+
first_filter = filters[0]
|
|
790
|
+
med_first_filter = data.query('filtercode==@first_filter')['mag'].median()
|
|
791
|
+
|
|
792
|
+
for filt in filters:
|
|
793
|
+
med_filtered = data.query('filtercode==@filt')['mag'].median()
|
|
794
|
+
data.loc[data['filtercode'] == filt,'mag'] += (med_first_filter-med_filtered)
|
|
795
|
+
yd=data['mag']
|
|
796
|
+
|
|
797
|
+
ts_time = Time(xd.to_numpy(), format='mjd')
|
|
798
|
+
ts_timeseries = TimeSeries(time=ts_time, meta={'object path': ts_path, 'object_name': ts_filename, 'frange': [[2, 60, 1500000]]})
|
|
799
|
+
|
|
800
|
+
ts_timeseries.add_column(yd.to_numpy()*y_unit, name='y')
|
|
801
|
+
ts_timeseries.add_column(ed.to_numpy()*cds.mag, name='y_err')
|
|
802
|
+
|
|
803
|
+
display_light_curve(ts_timeseries)
|
|
804
|
+
|
|
805
|
+
'''
|
|
806
|
+
f = open(default_file, 'w')
|
|
807
|
+
f.write(ts_path)
|
|
808
|
+
f.close()
|
|
809
|
+
'''
|
|
810
|
+
|
|
811
|
+
def getpowerspectrum(data):
|
|
812
|
+
from astropy.time import Time
|
|
813
|
+
from astropy.timeseries import TimeSeries
|
|
814
|
+
from astropy.units import cds
|
|
815
|
+
from astropy import units as u
|
|
816
|
+
|
|
817
|
+
file_name='lightcurve_data.csv'
|
|
818
|
+
data.to_csv(file_name,index=False)
|
|
819
|
+
|
|
820
|
+
file_path=os.path.join(os.getcwd(),file_name)
|
|
821
|
+
|
|
822
|
+
data.sort_values('hjd',inplace=True)
|
|
823
|
+
xd=data['hjd']-2400000.5
|
|
824
|
+
yd=data['mag']
|
|
825
|
+
ed=data['magerr']
|
|
826
|
+
|
|
827
|
+
y_unit=u.mag
|
|
828
|
+
|
|
829
|
+
filters = list(set(data['filtercode']))
|
|
830
|
+
first_filter = filters[0]
|
|
831
|
+
med_first_filter = data.query('filtercode==@first_filter')['mag'].median()
|
|
832
|
+
|
|
833
|
+
for filt in filters:
|
|
834
|
+
med_filtered = data.query('filtercode==@filt')['mag'].median()
|
|
835
|
+
data.loc[data['filtercode'] == filt,'mag'] += (med_first_filter-med_filtered)
|
|
836
|
+
yd=data['mag']
|
|
837
|
+
|
|
838
|
+
start_freq=0
|
|
839
|
+
final_freq=50
|
|
840
|
+
step_size=(final_freq-start_freq)/250000
|
|
841
|
+
|
|
842
|
+
th,freqs,frmax=pyaov.amhw(xd,yd,ed,final_freq,step_size)
|
|
843
|
+
|
|
844
|
+
plot=figure(width=400,height=400,title='ZTF Power Spectrum',x_axis_label=r'\[\text{Frequency [days}^{-1}]\]',y_axis_label=r'\[\text{Power}\]')
|
|
845
|
+
plot.line(x=freqs,y=th,color='black',line_width=0.5)
|
|
846
|
+
|
|
847
|
+
return plot
|