tree wide: way too many changes, im sorry
This commit is contained in:
@@ -62,6 +62,7 @@ class AstrodataGUI(QtWidgets.QMainWindow):
|
|||||||
self.btOpenSavedFlareCountFile.clicked.connect(self.btOpenSavedFlareCountFileClicked)
|
self.btOpenSavedFlareCountFile.clicked.connect(self.btOpenSavedFlareCountFileClicked)
|
||||||
|
|
||||||
self.flaredetectorPreview.periodsCalculated.connect(self.updatePeriods)
|
self.flaredetectorPreview.periodsCalculated.connect(self.updatePeriods)
|
||||||
|
self.flaredetectorPreview.epochCalculated.connect(self.updateEpochPeriod)
|
||||||
|
|
||||||
self.setupCustomSimbadQueries()
|
self.setupCustomSimbadQueries()
|
||||||
self.show()
|
self.show()
|
||||||
@@ -205,6 +206,9 @@ class AstrodataGUI(QtWidgets.QMainWindow):
|
|||||||
def updatePeriods(self, periods: list):
|
def updatePeriods(self, periods: list):
|
||||||
self.edPlotFoldPeriod.setText(str(periods[0].value))
|
self.edPlotFoldPeriod.setText(str(periods[0].value))
|
||||||
|
|
||||||
|
def updateEpochPeriod(self, epoch: float):
|
||||||
|
self.edPlotFoldEpochTime.setText(str(epoch))
|
||||||
|
|
||||||
def btCombineSeqClicked(self):
|
def btCombineSeqClicked(self):
|
||||||
#self.gbPlotOptionsNormalize.setEnabled(False)
|
#self.gbPlotOptionsNormalize.setEnabled(False)
|
||||||
mainName = self.listDownloaded.currentItem().text()
|
mainName = self.listDownloaded.currentItem().text()
|
||||||
|
|||||||
@@ -4,32 +4,54 @@ import concurrent.futures
|
|||||||
from ..util.MinimalLightCurve import read
|
from ..util.MinimalLightCurve import read
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from ..flaredetector.flaredetector import calculateFlareFitsForLightcurve
|
from ..flaredetector.flaredetector import calculateFlareFitsForLightcurve
|
||||||
from ..flaredetector.util import getTotalValidDataInSeconds
|
from ..flaredetector.util import *
|
||||||
|
|
||||||
def getFlareCount(filesDict):
|
def getFlareCount(filesDict):
|
||||||
lc = read(filesDict["FilePath"])
|
lc = read(filesDict["FilePath"])
|
||||||
lc.flux = lc["sap_flux"]
|
lc.flux = lc["sap_flux"]
|
||||||
lc.flux_err = lc["sap_flux_err"]
|
lc.flux_err = lc["sap_flux_err"]
|
||||||
sapPeaks, sapFits = calculateFlareFitsForLightcurve(lc.flatten(), minimalLC=True)
|
sapPeaks, sapFits = calculateFlareFitsForLightcurve(lc.flatten())
|
||||||
sapValSec, sapTds = getTotalValidDataInSeconds(lc, "sap_flux")
|
sapValSec, sapTds = getTotalValidDataInSeconds(lc, "sap_flux")
|
||||||
|
sapPeriodogram = lc.to_periodogram()
|
||||||
|
sapPeakPeriod = sapPeriodogram.period[findMaxIndices(sapPeriodogram, num=4, distance=100, sortByHighest=True)[0]]
|
||||||
|
sapEpochTime = getEpochTime(lc)
|
||||||
|
sapFoldedLC = lc.fold(period=sapPeakPeriod, epoch_time=sapEpochTime)
|
||||||
|
sapPhase, sapSineFit, sapFitType = getFoldedBestFit(sapFoldedLC)
|
||||||
|
sapMinima, sapMaxima = getFoldedFitPeakValley(sapSineFit)
|
||||||
|
sapminPhasesBoundsIndices, sapmaxPhasesBoundsIndices = getPhaseRangesNearPeak((sapMinima, sapMaxima), sapPhase)
|
||||||
lc.flux = lc["pdcsap_flux"]
|
lc.flux = lc["pdcsap_flux"]
|
||||||
lc.flux_err = lc["pdcsap_flux_err"]
|
lc.flux_err = lc["pdcsap_flux_err"]
|
||||||
pdcsapPeaks, pdcsapFits = calculateFlareFitsForLightcurve(lc.flatten(), minimalLC=True)
|
pdcsapPeaks, pdcsapFits = calculateFlareFitsForLightcurve(lc.flatten())
|
||||||
pdcsapValSec, pdcsapTds = getTotalValidDataInSeconds(lc, "pdcsap_flux")
|
pdcsapValSec, pdcsapTds = getTotalValidDataInSeconds(lc, "pdcsap_flux")
|
||||||
|
pdcsapPeriodogram = lc.to_periodogram()
|
||||||
|
pdcsapPeakPeriod = pdcsapPeriodogram.period[findMaxIndices(pdcsapPeriodogram, num=4, distance=100, sortByHighest=True)[0]]
|
||||||
|
pdcsapEpochTime = getEpochTime(lc)
|
||||||
|
pdcsapFoldedLC = lc.fold(period=pdcsapPeakPeriod, epoch_time=pdcsapEpochTime)
|
||||||
|
pdcsapPhase, pdcsapSineFit, pdcsapFitType = getFoldedBestFit(pdcsapFoldedLC)
|
||||||
|
pdcsapMinima, pdcsapMaxima = getFoldedFitPeakValley(pdcsapSineFit)
|
||||||
|
pdcsapminPhasesBoundsIndices, pdcsapmaxPhasesBoundsIndices = getPhaseRangesNearPeak((pdcsapMinima, pdcsapMaxima), pdcsapPhase)
|
||||||
|
|
||||||
filesDict["sapPeaks"] = sapPeaks
|
filesDict["sapPeaks"] = sapPeaks
|
||||||
filesDict["sapPeaksCount"] = len(sapPeaks)
|
filesDict["sapPeaksCount"] = len(sapPeaks)
|
||||||
filesDict["sapFits"] = sapFits
|
filesDict["sapFits"] = sapFits
|
||||||
filesDict["sapValidTimespans"] = sapTds
|
filesDict["sapValidTimespans"] = sapTds
|
||||||
filesDict["sapValidSeconds"] = sapValSec
|
filesDict["sapValidSeconds"] = sapValSec
|
||||||
|
filesDict["sapPeriod"] = sapPeakPeriod.value
|
||||||
|
filesDict["sapPeriodMinima"] = sapMinima
|
||||||
|
filesDict["sapPeriodMinimaBoundaries"] = sapminPhasesBoundsIndices
|
||||||
|
filesDict["sapPeriodMaxima"] = sapMaxima
|
||||||
|
filesDict["sapPeriodMaximaBoundaries"] = sapmaxPhasesBoundsIndices
|
||||||
filesDict["pdcsapPeaks"] = pdcsapPeaks
|
filesDict["pdcsapPeaks"] = pdcsapPeaks
|
||||||
filesDict["pdcsapPeaksCount"] = len(pdcsapPeaks)
|
filesDict["pdcsapPeaksCount"] = len(pdcsapPeaks)
|
||||||
filesDict["pdcsapFits"] = pdcsapFits
|
filesDict["pdcsapFits"] = pdcsapFits
|
||||||
filesDict["pdcsapValidTimespans"] = pdcsapTds
|
filesDict["pdcsapValidTimespans"] = pdcsapTds
|
||||||
filesDict["pdcsapValidSeconds"] = pdcsapValSec
|
filesDict["pdcsapValidSeconds"] = pdcsapValSec
|
||||||
|
filesDict["pdcsapPeriod"] = pdcsapPeakPeriod.value
|
||||||
|
filesDict["pdcsapPeriodMinima"] = pdcsapMinima
|
||||||
|
filesDict["pdcsapPeriodMinimaBoundaries"] = pdcsapminPhasesBoundsIndices
|
||||||
|
filesDict["pdcsapPeriodMaxima"] = pdcsapMaxima
|
||||||
|
filesDict["pdcsapPeriodMaximaBoundaries"] = pdcsapmaxPhasesBoundsIndices
|
||||||
del lc
|
del lc
|
||||||
if(filesDict["StarName"] == "CD-51 13128" and filesDict["Sequence"] == 1):
|
|
||||||
print(filesDict)
|
|
||||||
return filesDict
|
return filesDict
|
||||||
|
|
||||||
class CalcAllFlaresThread(QThread):
|
class CalcAllFlaresThread(QThread):
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ class FlareSummaryPlotGUI(QWidget):
|
|||||||
self.btShowFlaresPerStar.clicked.connect(self.btShowFlaresPerStarClicked)
|
self.btShowFlaresPerStar.clicked.connect(self.btShowFlaresPerStarClicked)
|
||||||
self.btShowFlaresPerStarNormalized = QPushButton("Show Flares/Star Normalized")
|
self.btShowFlaresPerStarNormalized = QPushButton("Show Flares/Star Normalized")
|
||||||
self.btShowFlaresPerStarNormalized.clicked.connect(self.btShowFlaresPerStarNormalizedClicked)
|
self.btShowFlaresPerStarNormalized.clicked.connect(self.btShowFlaresPerStarNormalizedClicked)
|
||||||
|
self.btShowPeriods = QPushButton("Show Mean Periods")
|
||||||
|
self.btShowPeriods.clicked.connect(self.btShowPeriodsClicked)
|
||||||
|
|
||||||
self.cbKepler = QCheckBox("Kepler")
|
self.cbKepler = QCheckBox("Kepler")
|
||||||
self.cbKepler.setChecked(True)
|
self.cbKepler.setChecked(True)
|
||||||
@@ -68,6 +70,7 @@ class FlareSummaryPlotGUI(QWidget):
|
|||||||
self.buttonGridLayout.addWidget(self.btShowFlaresPerFile, 0, 1)
|
self.buttonGridLayout.addWidget(self.btShowFlaresPerFile, 0, 1)
|
||||||
self.buttonGridLayout.addWidget(self.btShowFlaresPerStar, 0, 2)
|
self.buttonGridLayout.addWidget(self.btShowFlaresPerStar, 0, 2)
|
||||||
self.buttonGridLayout.addWidget(self.btShowFlaresPerStarNormalized, 0, 3)
|
self.buttonGridLayout.addWidget(self.btShowFlaresPerStarNormalized, 0, 3)
|
||||||
|
self.buttonGridLayout.addWidget(self.btShowPeriods, 0, 4)
|
||||||
|
|
||||||
self.buttonGridLayout.addWidget(QLabel("Sources: "), 1, 0)
|
self.buttonGridLayout.addWidget(QLabel("Sources: "), 1, 0)
|
||||||
self.buttonGridLayout.addWidget(self.cbKepler, 1, 1)
|
self.buttonGridLayout.addWidget(self.cbKepler, 1, 1)
|
||||||
@@ -169,7 +172,18 @@ class FlareSummaryPlotGUI(QWidget):
|
|||||||
'pdcsapFits',
|
'pdcsapFits',
|
||||||
'pdcsapPeaks',
|
'pdcsapPeaks',
|
||||||
'sapFits',
|
'sapFits',
|
||||||
'sapPeaks'])
|
'sapPeaks',
|
||||||
|
'sapPeriod',
|
||||||
|
'sapPeriodMinima',
|
||||||
|
'sapPeriodMinimaBoundaries',
|
||||||
|
'sapPeriodMaxima',
|
||||||
|
'sapPeriodMaximaBoundaries',
|
||||||
|
'pdcsapValidTimespans',
|
||||||
|
'pdcsapPeriod',
|
||||||
|
'pdcsapPeriodMinima',
|
||||||
|
'pdcsapPeriodMinimaBoundaries',
|
||||||
|
'pdcsapPeriodMaxima',
|
||||||
|
'pdcsapPeriodMaximaBoundaries'])
|
||||||
|
|
||||||
showSourceFilter = np.full(len(data), False)
|
showSourceFilter = np.full(len(data), False)
|
||||||
|
|
||||||
@@ -248,7 +262,19 @@ class FlareSummaryPlotGUI(QWidget):
|
|||||||
'pdcsapFits',
|
'pdcsapFits',
|
||||||
'pdcsapPeaks',
|
'pdcsapPeaks',
|
||||||
'sapFits',
|
'sapFits',
|
||||||
'sapPeaks'])
|
'sapValidTimespans',
|
||||||
|
'sapPeaks',
|
||||||
|
'sapPeriod',
|
||||||
|
'sapPeriodMinima',
|
||||||
|
'sapPeriodMinimaBoundaries',
|
||||||
|
'sapPeriodMaxima',
|
||||||
|
'sapPeriodMaximaBoundaries',
|
||||||
|
'pdcsapValidTimespans',
|
||||||
|
'pdcsapPeriod',
|
||||||
|
'pdcsapPeriodMinima',
|
||||||
|
'pdcsapPeriodMinimaBoundaries',
|
||||||
|
'pdcsapPeriodMaxima',
|
||||||
|
'pdcsapPeriodMaximaBoundaries'])
|
||||||
|
|
||||||
showSourceFilter = np.full(len(data), False)
|
showSourceFilter = np.full(len(data), False)
|
||||||
|
|
||||||
@@ -330,3 +356,120 @@ class FlareSummaryPlotGUI(QWidget):
|
|||||||
self.figureAxis.set_xlabel("Star Number")
|
self.figureAxis.set_xlabel("Star Number")
|
||||||
self.figureAxis.legend()
|
self.figureAxis.legend()
|
||||||
self.figure.canvas.draw_idle()
|
self.figure.canvas.draw_idle()
|
||||||
|
|
||||||
|
def btShowPeriodsClicked(self):
|
||||||
|
data = self.starFLareDictList.drop(columns=['Distance',
|
||||||
|
'DistanceUnit',
|
||||||
|
'FilePath',
|
||||||
|
'RotVel',
|
||||||
|
'RotVelUnit',
|
||||||
|
'Sequence',
|
||||||
|
'pdcsapFits',
|
||||||
|
'pdcsapPeaks',
|
||||||
|
'sapFits',
|
||||||
|
'sapValidTimespans',
|
||||||
|
'sapPeaks',
|
||||||
|
'sapPeriodMinima',
|
||||||
|
'sapPeriodMinimaBoundaries',
|
||||||
|
'sapPeriodMaxima',
|
||||||
|
'sapPeriodMaximaBoundaries',
|
||||||
|
'pdcsapValidTimespans',
|
||||||
|
'pdcsapPeriodMinima',
|
||||||
|
'pdcsapPeriodMinimaBoundaries',
|
||||||
|
'pdcsapPeriodMaxima',
|
||||||
|
'pdcsapPeriodMaximaBoundaries',
|
||||||
|
'sapPeaksCount',
|
||||||
|
'pdcsapPeaksCount',
|
||||||
|
'sapValidSeconds',
|
||||||
|
'pdcsapValidSeconds'])
|
||||||
|
|
||||||
|
showSourceFilter = np.full(len(data), False)
|
||||||
|
|
||||||
|
if(self.cbKepler.isChecked()):
|
||||||
|
showKepler = data["Source"] == "Kepler"
|
||||||
|
showSourceFilter |= showKepler
|
||||||
|
if(self.cbK2.isChecked()):
|
||||||
|
showK2 = data["Source"] == "K2"
|
||||||
|
showSourceFilter |= showK2
|
||||||
|
if(self.cbTESS.isChecked()):
|
||||||
|
showTESS = data["Source"] == "TESS"
|
||||||
|
showSourceFilter |= showTESS
|
||||||
|
|
||||||
|
print(data["sapPeriod"])
|
||||||
|
|
||||||
|
data = data[showSourceFilter].groupby(["StarName", "SpType"],
|
||||||
|
as_index=False).agg({"sapPeriod": "mean",
|
||||||
|
"pdcsapPeriod": "mean"})
|
||||||
|
x = np.arange(start=1, stop=len(data)+1, step=1, dtype=int)
|
||||||
|
|
||||||
|
if(self.cbSpTypeL.isChecked()):
|
||||||
|
Lfilter = data["SpType"].str.startswith("L")
|
||||||
|
Lfilter &= showSourceFilter
|
||||||
|
if(self.cbSpTypeM.isChecked()):
|
||||||
|
Mfilter = data["SpType"].str.startswith("M")
|
||||||
|
Mfilter &= showSourceFilter
|
||||||
|
if(self.cbSpTypeK.isChecked()):
|
||||||
|
Kfilter = data["SpType"].str.startswith("K")
|
||||||
|
Kfilter &= showSourceFilter
|
||||||
|
if(self.cbSpTypeG.isChecked()):
|
||||||
|
Gfilter = data["SpType"].str.startswith("G")
|
||||||
|
Gfilter &= showSourceFilter
|
||||||
|
if(self.cbSpTypeF.isChecked()):
|
||||||
|
Ffilter = data["SpType"].str.startswith("F")
|
||||||
|
Ffilter &= showSourceFilter
|
||||||
|
if(self.cbSpTypeUnknown.isChecked()):
|
||||||
|
Unknownfilter = data["SpType"].str.startswith("-")
|
||||||
|
Unknownfilter &= showSourceFilter
|
||||||
|
|
||||||
|
self.figureAxis.clear()
|
||||||
|
if(self.cbSpTypeL.isChecked()):
|
||||||
|
if(np.any(Lfilter)):
|
||||||
|
self.figureAxis.scatter(x[Lfilter], data[Lfilter]["sapPeriod"],
|
||||||
|
marker="o", color="brown", label="L SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Lfilter], data[Lfilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="brown", label="L PDCSAP Period")
|
||||||
|
if(self.cbSpTypeM.isChecked()):
|
||||||
|
if(np.any(Mfilter)):
|
||||||
|
self.figureAxis.scatter(x[Mfilter], data[Mfilter]["sapPeriod"],
|
||||||
|
marker="o", color="red", label="M SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Mfilter], data[Mfilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="red", label="M PDCSAP Period")
|
||||||
|
if(self.cbSpTypeK.isChecked()):
|
||||||
|
if(np.any(Kfilter)):
|
||||||
|
self.figureAxis.scatter(x[Kfilter], data[Kfilter]["sapPeriod"],
|
||||||
|
marker="o", color="orange", label="K SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Kfilter], data[Kfilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="orange", label="K PDCSAP Period")
|
||||||
|
if(self.cbSpTypeG.isChecked()):
|
||||||
|
if(np.any(Gfilter)):
|
||||||
|
self.figureAxis.scatter(x[Gfilter], data[Gfilter]["sapPeriod"],
|
||||||
|
marker="o", color="yellow", label="G SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Gfilter], data[Gfilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="yellow", label="G PDCSAP Period")
|
||||||
|
if(self.cbSpTypeF.isChecked()):
|
||||||
|
if(np.any(Ffilter)):
|
||||||
|
self.figureAxis.scatter(x[Ffilter], data[Ffilter]["sapPeriod"],
|
||||||
|
marker="o", color="greenyellow", label="F SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Ffilter], data[Ffilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="greenyellow", label="F PDCSAP Period")
|
||||||
|
if(self.cbSpTypeUnknown.isChecked()):
|
||||||
|
if(np.any(Unknownfilter)):
|
||||||
|
self.figureAxis.scatter(x[Unknownfilter], data[Unknownfilter]["sapPeriod"],
|
||||||
|
marker="o", color="gray", label="Unknown SAP Period")
|
||||||
|
self.figureAxis.scatter(x[Unknownfilter], data[Unknownfilter]["pdcsapPeriod"],
|
||||||
|
marker="x", color="gray", label="Unknown PDCSAP Period")
|
||||||
|
|
||||||
|
self.figureAxis.set_ylabel("Period / days")
|
||||||
|
self.figureAxis.set_xlabel("Star Number")
|
||||||
|
self.figureAxis.legend()
|
||||||
|
self.figure.canvas.draw_idle()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def btShowNumMinimaMaximaClicked(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def btShowFlaresInMinimaMaximaClicked(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def btShowFlaresInMinimaMaximaPerMinimaMaximaClicked(self):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ class FlaredetectorWidget(QtWidgets.QWidget):
|
|||||||
cycle, foldedIndex = convertStarndardIndexToFoldedIndex(lc, peak["StandardIndex"])
|
cycle, foldedIndex = convertStarndardIndexToFoldedIndex(lc, peak["StandardIndex"])
|
||||||
self.figureAxis.plot(lc.phase[lc.cycle == cycle][foldedIndex].value,
|
self.figureAxis.plot(lc.phase[lc.cycle == cycle][foldedIndex].value,
|
||||||
lc.flux[lc.cycle == cycle][foldedIndex], "x", color="red")
|
lc.flux[lc.cycle == cycle][foldedIndex], "x", color="red")
|
||||||
phase, sineFit = getFoldedBestFit(lc)
|
phase, sineFit, _ = getFoldedBestFit(lc)
|
||||||
self.figureAxis.plot(phase, sineFit, color="red")
|
self.figureAxis.plot(phase, sineFit, color="red")
|
||||||
minPhasesBoundsIndices, maxPhasesBoundsIndices = getPhaseRangesNearPeak(getFoldedFitPeakValley(sineFit), phase)
|
minPhasesBoundsIndices, maxPhasesBoundsIndices = getPhaseRangesNearPeak(getFoldedFitPeakValley(sineFit), phase)
|
||||||
plotPhaseRangesNearPeak((minPhasesBoundsIndices, maxPhasesBoundsIndices), phase, ax=self.figureAxis)
|
plotPhaseRangesNearPeak((minPhasesBoundsIndices, maxPhasesBoundsIndices), phase, ax=self.figureAxis)
|
||||||
|
|||||||
@@ -37,12 +37,19 @@ def calculateFitForFlare(lightcurve, peakIndex):
|
|||||||
popt, pcov = curve_fit(lambda x, l, w: GaussExpo(x, Peak, l, w), flareFitDataPoints, flareData)
|
popt, pcov = curve_fit(lambda x, l, w: GaussExpo(x, Peak, l, w), flareFitDataPoints, flareData)
|
||||||
pcovDiag = np.diag(pcov)
|
pcovDiag = np.diag(pcov)
|
||||||
fit = GaussExpo(flareFitDataPoints, Peak, *popt)
|
fit = GaussExpo(flareFitDataPoints, Peak, *popt)
|
||||||
|
rss = compureRSS(fit, flareData)
|
||||||
|
aic = computeAIC(rss, 2, len(flareData))
|
||||||
|
bic = computeBIC(rss, 2, len(flareData))
|
||||||
|
r2 = 1 - rss/computeTotalSoS(flareData)
|
||||||
|
#print("Fit r2: ", r2)
|
||||||
|
if(r2 < 0.8):
|
||||||
|
raise Exception("Fit varies too much")
|
||||||
flareFitDataPoints = flareFitDataPoints + peakIndex
|
flareFitDataPoints = flareFitDataPoints + peakIndex
|
||||||
return np.array(Peak+1), flareFitDataPoints, np.array(fit+1)
|
return np.array(Peak+1), flareFitDataPoints, np.array(fit+1)
|
||||||
|
|
||||||
def calculateFlareFitsForLightcurve(lightcurve, num=100, distance=1, height=0.05, minimalLC=False):
|
def calculateFlareFitsForLightcurve(lightcurve, num=100, distance=1, height=0.05):
|
||||||
maxIndices = findMaxIndices(lightcurve, num, distance=distance, height=height,
|
maxIndices = findMaxIndices(lightcurve, num, distance=distance, height=height,
|
||||||
sortByHighest=True, minimalLC=minimalLC)
|
sortByHighest=True)
|
||||||
peaks = []
|
peaks = []
|
||||||
fits = []
|
fits = []
|
||||||
for index in maxIndices:
|
for index in maxIndices:
|
||||||
|
|||||||
+111
-76
@@ -1,21 +1,15 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy.polynomial.polynomial import Polynomial
|
from numpy.polynomial.polynomial import Polynomial
|
||||||
from scipy.signal import find_peaks
|
from scipy.signal import find_peaks, argrelextrema
|
||||||
from scipy.optimize import curve_fit
|
from scipy.optimize import curve_fit
|
||||||
|
|
||||||
def findMaxIndices(lc, num=3, distance=100, height=(None, None), sortByHighest=False,
|
def findMaxIndices(lc, num=3, distance=100, height=(None, None), sortByHighest=False):
|
||||||
minimalLC=False):
|
if(hasattr(lc, "power")):
|
||||||
if(minimalLC):
|
data = lc.power
|
||||||
|
elif(hasattr(lc, "flux")):
|
||||||
data = lc.flux
|
data = lc.flux
|
||||||
else:
|
else:
|
||||||
from lightkurve.periodogram import Periodogram as OrigPG
|
return np.zeros(num)-1
|
||||||
from lightkurve.lightcurve import LightCurve as OrigLC
|
|
||||||
if(isinstance(lc, OrigPG)):
|
|
||||||
data = lc.power
|
|
||||||
elif(isinstance(lc, OrigLC)):
|
|
||||||
data = lc.flux
|
|
||||||
else:
|
|
||||||
return np.zeros(num)-1
|
|
||||||
peak_indices, peak_dict = find_peaks(data, height=height,
|
peak_indices, peak_dict = find_peaks(data, height=height,
|
||||||
distance=distance)
|
distance=distance)
|
||||||
peak_heights = peak_dict["peak_heights"]
|
peak_heights = peak_dict["peak_heights"]
|
||||||
@@ -88,16 +82,22 @@ def singleSine(t, A, w, p, c):
|
|||||||
|
|
||||||
def fitSingleSine(phase, flux):
|
def fitSingleSine(phase, flux):
|
||||||
initGuess = [np.ptp(flux)/2, 2 * np.pi / (np.max(phase) - np.min(phase)), 0, np.mean(flux)]
|
initGuess = [np.ptp(flux)/2, 2 * np.pi / (np.max(phase) - np.min(phase)), 0, np.mean(flux)]
|
||||||
popt, _ = curve_fit(singleSine, phase, flux, p0=initGuess, maxfev=100000)
|
popt, _ = curve_fit(singleSine, phase, flux, p0=initGuess, maxfev=300)
|
||||||
return singleSine(phase, *popt)
|
return singleSine(phase, *popt)
|
||||||
|
|
||||||
|
def polynomial(phase, flux, degree):
|
||||||
|
return Polynomial.fit(phase, flux, degree).convert().coef
|
||||||
|
|
||||||
def fitPolynomial(phase, flux, degree):
|
def fitPolynomial(phase, flux, degree):
|
||||||
return sum(p * phase**i for i, p in enumerate(Polynomial.fit(phase, flux, degree).convert().coef))
|
return sum(p * phase**i for i, p in enumerate(polynomial(phase, flux, degree)))
|
||||||
|
|
||||||
def compureRSS(fit, flux):
|
def compureRSS(fit, flux):
|
||||||
residuals = flux - fit
|
residuals = flux - fit
|
||||||
return np.sum(residuals**2)
|
return np.sum(residuals**2)
|
||||||
|
|
||||||
|
def computeTotalSoS(flux):
|
||||||
|
return np.sum((flux - np.mean(flux))**2)
|
||||||
|
|
||||||
def computeAIC(rss, numParams, numDataPoints):
|
def computeAIC(rss, numParams, numDataPoints):
|
||||||
return 2 * numParams + numDataPoints * np.log(rss/numDataPoints)
|
return 2 * numParams + numDataPoints * np.log(rss/numDataPoints)
|
||||||
|
|
||||||
@@ -113,30 +113,46 @@ def getFoldedBestFit(foldedLc):
|
|||||||
flux = foldedLc.normalize().flux
|
flux = foldedLc.normalize().flux
|
||||||
phase = foldedLc.phase[filt].value
|
phase = foldedLc.phase[filt].value
|
||||||
flux = flux[filt]
|
flux = flux[filt]
|
||||||
#popt, pcov = curve_fit(sine, phase, flux[filt], maxfev=100000)
|
polyDegree = 7
|
||||||
singleFit = fitSingleSine(phase, flux)
|
fitThreshold = 0.0
|
||||||
polyFit = fitPolynomial(phase, flux, 10)
|
smoothed_flux = np.convolve(flux, np.ones(len(flux)//100)/(len(flux)//100), mode="valid")
|
||||||
|
peaks, _ = find_peaks(smoothed_flux, height=np.mean(smoothed_flux))
|
||||||
|
#print("Num peaks: ", peaks)
|
||||||
|
|
||||||
singleRSS = compureRSS(singleFit, flux)
|
try:
|
||||||
polyRSS = compureRSS(polyFit, flux)
|
retFit = fitSingleSine(phase, flux)
|
||||||
|
r2 = 1 - (compureRSS(retFit, flux)/computeTotalSoS(flux))
|
||||||
|
fitType = "sine"
|
||||||
|
#print("R2: ", r2)
|
||||||
|
if(r2 < fitThreshold):
|
||||||
|
raise Exception("Sine fit is suboptimal")
|
||||||
|
#print("Single sine preferred")
|
||||||
|
except:
|
||||||
|
retFit = fitPolynomial(phase, flux, polyDegree)
|
||||||
|
fitType = "poly"
|
||||||
|
#print("Polynomial preferred")
|
||||||
|
|
||||||
singleAIC = computeAIC(singleRSS, 4, len(flux))
|
retFit *= multi
|
||||||
singleBIC = computeBIC(singleRSS, 4, len(flux))
|
return phase, retFit, fitType
|
||||||
polyAIC = computeAIC(polyRSS, 10, len(flux))
|
|
||||||
polyBIC = computeBIC(polyRSS, 10, len(flux))
|
|
||||||
|
|
||||||
if (singleAIC < polyAIC and singleBIC < polyBIC):
|
|
||||||
print("Single sine preferred")
|
|
||||||
sineFit = singleFit
|
|
||||||
else:
|
|
||||||
print("Polynomial preferred")
|
|
||||||
sineFit = polyFit
|
|
||||||
|
|
||||||
sineFit *= multi
|
|
||||||
return phase, sineFit
|
|
||||||
|
|
||||||
def getFoldedFitPeakValley(sineFit):
|
def getFoldedFitPeakValley(sineFit):
|
||||||
return np.argmin(sineFit), np.argmax(sineFit)
|
minima = argrelextrema(sineFit, np.less)[0]
|
||||||
|
maxima = argrelextrema(sineFit, np.greater)[0]
|
||||||
|
#print(minima)
|
||||||
|
#print(maxima)
|
||||||
|
if(len(minima) > 0 and len(maxima) > 0):
|
||||||
|
if(minima[0] < maxima[0] and minima[-1] > maxima[-1]):
|
||||||
|
if(sineFit[minima[0]] > sineFit[minima[-1]]):
|
||||||
|
minima = np.delete(minima, 0)
|
||||||
|
else:
|
||||||
|
minima = np.delete(minima, -1)
|
||||||
|
elif(maxima[0] < minima[0] and maxima[-1] > minima[-1]):
|
||||||
|
if(sineFit[maxima[0]] > sineFit[maxima[-1]]):
|
||||||
|
maxima = np.delete(maxima, -1)
|
||||||
|
else:
|
||||||
|
maxima = np.delete(maxima, 0)
|
||||||
|
|
||||||
|
return minima, maxima
|
||||||
|
|
||||||
def findNearestIndexOfValue(array, value):
|
def findNearestIndexOfValue(array, value):
|
||||||
array = np.asarray(array)
|
array = np.asarray(array)
|
||||||
@@ -144,57 +160,76 @@ def findNearestIndexOfValue(array, value):
|
|||||||
return idx
|
return idx
|
||||||
|
|
||||||
def getPhaseRangesNearPeak(maxArgs, phase):
|
def getPhaseRangesNearPeak(maxArgs, phase):
|
||||||
minPhase = phase[maxArgs[0]]
|
minPhases = phase[maxArgs[0]]
|
||||||
maxPhase = phase[maxArgs[1]]
|
maxPhases = phase[maxArgs[1]]
|
||||||
totalPhase = abs(phase[0]) + abs(phase[-1])
|
totalPhase = abs(phase[0]) + abs(phase[-1])
|
||||||
|
|
||||||
phasePart = totalPhase * 0.3 / 2
|
phasePart = totalPhase * 0.3 / (len(minPhases) + len(maxPhases))
|
||||||
minPhaseBounds = []
|
minPhasesBounds = []
|
||||||
if(minPhase - phasePart < phase[0]):
|
for minPhase in minPhases:
|
||||||
minPhaseBounds.append((phase[0], minPhase + phasePart))
|
minPhaseBounds = []
|
||||||
minPhaseBounds.append((phase[-1] + (minPhase - phasePart - phase[0]), phase[-1]))
|
if(minPhase - phasePart < phase[0]):
|
||||||
elif(minPhase + phasePart > phase[-1]):
|
minPhaseBounds.append((phase[0], minPhase + phasePart))
|
||||||
minPhaseBounds.append((minPhase - phasePart, phase[-1]))
|
minPhaseBounds.append((phase[-1] + (minPhase - phasePart - phase[0]), phase[-1]))
|
||||||
minPhaseBounds.append((phase[0], phase[0] + (minPhase + phasePart - phase[-1])))
|
elif(minPhase + phasePart > phase[-1]):
|
||||||
else:
|
minPhaseBounds.append((minPhase - phasePart, phase[-1]))
|
||||||
minPhaseBounds.append((minPhase - phasePart, minPhase + phasePart))
|
minPhaseBounds.append((phase[0], phase[0] + (minPhase + phasePart - phase[-1])))
|
||||||
|
else:
|
||||||
|
minPhaseBounds.append((minPhase - phasePart, minPhase + phasePart))
|
||||||
|
minPhasesBounds.append(minPhaseBounds)
|
||||||
|
|
||||||
maxPhaseBounds = []
|
maxPhasesBounds = []
|
||||||
if(maxPhase - phasePart < phase[0]):
|
for maxPhase in maxPhases:
|
||||||
maxPhaseBounds.append((phase[0], maxPhase + phasePart))
|
maxPhaseBounds = []
|
||||||
maxPhaseBounds.append((phase[-1] + (maxPhase - phasePart - phase[0]), phase[-1]))
|
if(maxPhase - phasePart < phase[0]):
|
||||||
elif(maxPhase + phasePart > phase[-1]):
|
maxPhaseBounds.append((phase[0], maxPhase + phasePart))
|
||||||
maxPhaseBounds.append((maxPhase - phasePart, phase[-1]))
|
maxPhaseBounds.append((phase[-1] + (maxPhase - phasePart - phase[0]), phase[-1]))
|
||||||
maxPhaseBounds.append((phase[0], phase[0] + (maxPhase + phasePart - phase[-1])))
|
elif(maxPhase + phasePart > phase[-1]):
|
||||||
else:
|
maxPhaseBounds.append((maxPhase - phasePart, phase[-1]))
|
||||||
maxPhaseBounds.append((maxPhase - phasePart, maxPhase + phasePart))
|
maxPhaseBounds.append((phase[0], phase[0] + (maxPhase + phasePart - phase[-1])))
|
||||||
|
else:
|
||||||
|
maxPhaseBounds.append((maxPhase - phasePart, maxPhase + phasePart))
|
||||||
|
maxPhasesBounds.append(maxPhaseBounds)
|
||||||
|
|
||||||
minPhaseBoundsIndices = []
|
minPhasesBoundsIndices = []
|
||||||
for l in minPhaseBounds:
|
for minPhaseBounds in minPhasesBounds:
|
||||||
minPhaseBoundsIndices.append([findNearestIndexOfValue(phase, lv) for lv in l])
|
minPhaseBoundsIndices = []
|
||||||
|
for l in minPhaseBounds:
|
||||||
|
minPhaseBoundsIndices.append([findNearestIndexOfValue(phase, lv) for lv in l])
|
||||||
|
minPhasesBoundsIndices.append(minPhaseBoundsIndices)
|
||||||
|
|
||||||
maxPhaseBoundsIndices = []
|
maxPhasesBoundsIndices = []
|
||||||
for l in maxPhaseBounds:
|
for maxPhaseBounds in maxPhasesBounds:
|
||||||
maxPhaseBoundsIndices.append([findNearestIndexOfValue(phase, lv) for lv in l])
|
maxPhaseBoundsIndices = []
|
||||||
|
for l in maxPhaseBounds:
|
||||||
|
maxPhaseBoundsIndices.append([findNearestIndexOfValue(phase, lv) for lv in l])
|
||||||
|
maxPhasesBoundsIndices.append(maxPhaseBoundsIndices)
|
||||||
|
|
||||||
return minPhaseBoundsIndices, maxPhaseBoundsIndices
|
return minPhasesBoundsIndices, maxPhasesBoundsIndices
|
||||||
|
|
||||||
def plotPhaseRangesNearPeak(indices, phase, ax=None):
|
def plotPhaseRangesNearPeak(indices, phase, ax=None):
|
||||||
minPhaseBoundsIndices = indices[0]
|
minPhasesBoundsIndices = indices[0]
|
||||||
maxPhaseBoundsIndices = indices[1]
|
maxPhasesBoundsIndices = indices[1]
|
||||||
|
|
||||||
if(ax is None):
|
if(ax is None):
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
for pair in minPhaseBoundsIndices:
|
for minPhaseBoundsIndices in minPhasesBoundsIndices:
|
||||||
for l in pair:
|
for pair in minPhaseBoundsIndices:
|
||||||
plt.axes.axvline(phase[l], color="violet")
|
for l in pair:
|
||||||
for pair in maxPhaseBoundsIndices:
|
plt.axes.axvline(phase[l], color="violet")
|
||||||
for l in pair:
|
for maxPhaseBoundsIndices in maxPhasesBoundsIndices:
|
||||||
plt.axes.axvline(phase[l], color="orange")
|
for pair in maxPhaseBoundsIndices:
|
||||||
|
for l in pair:
|
||||||
|
plt.axes.axvline(phase[l], color="orange")
|
||||||
else:
|
else:
|
||||||
for pair in minPhaseBoundsIndices:
|
for minPhaseBoundsIndices in minPhasesBoundsIndices:
|
||||||
for l in pair:
|
for pair in minPhaseBoundsIndices:
|
||||||
ax.axvline(phase[l], color="violet")
|
for l in pair:
|
||||||
for pair in maxPhaseBoundsIndices:
|
ax.axvline(phase[l], color="violet")
|
||||||
for l in pair:
|
for maxPhaseBoundsIndices in maxPhasesBoundsIndices:
|
||||||
ax.axvline(phase[l], color="orange")
|
for pair in maxPhaseBoundsIndices:
|
||||||
|
for l in pair:
|
||||||
|
ax.axvline(phase[l], color="orange")
|
||||||
|
|
||||||
|
def getEpochTime(lc):
|
||||||
|
return lc.time.value[argrelextrema(np.asarray(lc.flux.value), np.less, order=500)[0]][0]
|
||||||
@@ -17,6 +17,10 @@ from astropy.time.formats import TimeFromEpoch
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class LightkurveWarning(Warning):
|
||||||
|
"""Class for all Lightkurve warnings."""
|
||||||
|
pass
|
||||||
|
|
||||||
class TimeBKJD(TimeFromEpoch):
|
class TimeBKJD(TimeFromEpoch):
|
||||||
name = 'bkjd'
|
name = 'bkjd'
|
||||||
unit = 1.0
|
unit = 1.0
|
||||||
@@ -402,6 +406,14 @@ class TessQualityFlags(QualityFlags):
|
|||||||
32768: "Insufficient Targets for Error Correction Exclude",
|
32768: "Insufficient Targets for Error Correction Exclude",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def validate_method(method, supported_methods):
|
||||||
|
method = method.lower()
|
||||||
|
if method in supported_methods:
|
||||||
|
return method
|
||||||
|
raise ValueError(
|
||||||
|
"method '{}' is not supported; "
|
||||||
|
"must be one of {}".format(method, supported_methods)
|
||||||
|
)
|
||||||
|
|
||||||
def _is_dict_like(data1):
|
def _is_dict_like(data1):
|
||||||
return hasattr(data1, "keys") and callable(getattr(data1, "keys"))
|
return hasattr(data1, "keys") and callable(getattr(data1, "keys"))
|
||||||
@@ -879,6 +891,195 @@ class LightCurve(TimeSeries):
|
|||||||
return flatten_lc, trend_lc
|
return flatten_lc, trend_lc
|
||||||
return flatten_lc
|
return flatten_lc
|
||||||
|
|
||||||
|
def to_periodogram(self, method="lombscargle", **kwargs):
|
||||||
|
supported_methods = ["ls", "bls", "lombscargle", "boxleastsquares"]
|
||||||
|
method = validate_method(method.replace(" ", ""), supported_methods)
|
||||||
|
if method in ["bls", "boxleastsquares"]:
|
||||||
|
from .MinimalPeriodogram import BoxLeastSquaresPeriodogram
|
||||||
|
|
||||||
|
return BoxLeastSquaresPeriodogram.from_lightcurve(lc=self, **kwargs)
|
||||||
|
else:
|
||||||
|
from .MinimalPeriodogram import LombScarglePeriodogram
|
||||||
|
|
||||||
|
return LombScarglePeriodogram.from_lightcurve(lc=self, **kwargs)
|
||||||
|
|
||||||
|
def fold(
|
||||||
|
self,
|
||||||
|
period=None,
|
||||||
|
epoch_time=None,
|
||||||
|
epoch_phase=0,
|
||||||
|
wrap_phase=None,
|
||||||
|
normalize_phase=False,
|
||||||
|
):
|
||||||
|
# Lightkurve v1.x assumed that `period` was given in days if no unit
|
||||||
|
# was specified. We maintain this behavior for backwards-compatibility.
|
||||||
|
if period is not None and not isinstance(period, Quantity):
|
||||||
|
period *= u.day
|
||||||
|
if epoch_time is not None and not isinstance(epoch_time, Time):
|
||||||
|
epoch_time = Time(
|
||||||
|
epoch_time, format=self.time.format, scale=self.time.scale
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
epoch_phase is not None
|
||||||
|
and not isinstance(epoch_phase, Quantity)
|
||||||
|
and not normalize_phase
|
||||||
|
):
|
||||||
|
epoch_phase *= u.day
|
||||||
|
if wrap_phase is not None and not isinstance(wrap_phase, Quantity):
|
||||||
|
wrap_phase *= u.day
|
||||||
|
|
||||||
|
# Warn if `epoch_time` appears to use the wrong format
|
||||||
|
if epoch_time is not None and epoch_time.value > 2450000:
|
||||||
|
if self.time.format == "bkjd":
|
||||||
|
warnings.warn(
|
||||||
|
"`epoch_time` appears to be given in JD, "
|
||||||
|
"however the light curve time uses BKJD "
|
||||||
|
"(i.e. JD - 2454833).",
|
||||||
|
LightkurveWarning,
|
||||||
|
)
|
||||||
|
elif self.time.format == "btjd":
|
||||||
|
warnings.warn(
|
||||||
|
"`epoch_time` appears to be given in JD, "
|
||||||
|
"however the light curve time uses BTJD "
|
||||||
|
"(i.e. JD - 2457000).",
|
||||||
|
LightkurveWarning,
|
||||||
|
)
|
||||||
|
|
||||||
|
ts = super().fold(
|
||||||
|
period=period,
|
||||||
|
epoch_time=epoch_time,
|
||||||
|
epoch_phase=epoch_phase,
|
||||||
|
wrap_phase=wrap_phase,
|
||||||
|
normalize_phase=normalize_phase,
|
||||||
|
)
|
||||||
|
|
||||||
|
# The folded time would pass the `TimeSeries` validation check if
|
||||||
|
# `normalize_phase=True`, so creating a `FoldedLightCurve` object
|
||||||
|
# requires the following three-step workaround:
|
||||||
|
# 1. Give the folded light curve a valid time column again
|
||||||
|
with ts._delay_required_column_checks():
|
||||||
|
folded_time = ts.time.copy()
|
||||||
|
ts.remove_column("time")
|
||||||
|
ts.add_column(self.time, name="time", index=0)
|
||||||
|
# 2. Create the folded object
|
||||||
|
lc = FoldedLightCurve(data=ts)
|
||||||
|
# 3. Restore the folded time
|
||||||
|
with lc._delay_required_column_checks():
|
||||||
|
lc.remove_column("time")
|
||||||
|
lc.add_column(folded_time, name="time", index=0)
|
||||||
|
|
||||||
|
# Add extra column and meta data specific to FoldedLightCurve
|
||||||
|
lc.add_column(
|
||||||
|
self.time.copy(), name="time_original", index=len(self._required_columns)
|
||||||
|
)
|
||||||
|
lc.meta["PERIOD"] = period
|
||||||
|
lc.meta["EPOCH_TIME"] = epoch_time
|
||||||
|
lc.meta["EPOCH_PHASE"] = epoch_phase
|
||||||
|
lc.meta["WRAP_PHASE"] = wrap_phase
|
||||||
|
lc.meta["NORMALIZE_PHASE"] = normalize_phase
|
||||||
|
lc.sort("time")
|
||||||
|
|
||||||
|
return lc
|
||||||
|
|
||||||
|
def normalize(self, unit="unscaled"):
|
||||||
|
validate_method(unit, ["unscaled", "percent", "ppt", "ppm"])
|
||||||
|
median_flux = np.nanmedian(self.flux)
|
||||||
|
std_flux = np.nanstd(self.flux)
|
||||||
|
|
||||||
|
# If the median flux is within half a standard deviation from zero, the
|
||||||
|
# light curve is likely zero-centered and normalization makes no sense.
|
||||||
|
if (median_flux == 0) or (
|
||||||
|
np.isfinite(std_flux) and (np.abs(median_flux) < 0.5 * std_flux)
|
||||||
|
):
|
||||||
|
warnings.warn(
|
||||||
|
"The light curve appears to be zero-centered "
|
||||||
|
"(median={:.2e} +/- {:.2e}); `normalize()` will divide "
|
||||||
|
"the light curve by a value close to zero, which is "
|
||||||
|
"probably not what you want."
|
||||||
|
"".format(median_flux, std_flux),
|
||||||
|
LightkurveWarning,
|
||||||
|
)
|
||||||
|
# If the median flux is negative, normalization will invert the light
|
||||||
|
# curve and makes no sense.
|
||||||
|
if median_flux < 0:
|
||||||
|
warnings.warn(
|
||||||
|
"The light curve has a negative median flux ({:.2e});"
|
||||||
|
" `normalize()` will therefore divide by a negative "
|
||||||
|
"number and invert the light curve, which is probably"
|
||||||
|
"not what you want".format(median_flux),
|
||||||
|
LightkurveWarning,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a new light curve instance and normalize its values
|
||||||
|
lc = self.copy()
|
||||||
|
lc.flux = lc.flux / median_flux
|
||||||
|
lc.flux_err = lc.flux_err / median_flux
|
||||||
|
if not lc.flux.unit:
|
||||||
|
lc.flux *= u.dimensionless_unscaled
|
||||||
|
if not lc.flux_err.unit:
|
||||||
|
lc.flux_err *= u.dimensionless_unscaled
|
||||||
|
|
||||||
|
# Set the desired relative (dimensionless) units
|
||||||
|
if unit == "percent":
|
||||||
|
lc.flux = lc.flux.to(u.percent)
|
||||||
|
lc.flux_err = lc.flux_err.to(u.percent)
|
||||||
|
elif unit in ("ppt", "ppm"):
|
||||||
|
lc.flux = lc.flux.to(unit)
|
||||||
|
lc.flux_err = lc.flux_err.to(unit)
|
||||||
|
|
||||||
|
lc.meta["NORMALIZED"] = True
|
||||||
|
return lc
|
||||||
|
|
||||||
|
def remove_nans(self, column: str = "flux"):
|
||||||
|
return self[~np.isnan(self[column])] # This will return a sliced copy
|
||||||
|
|
||||||
|
class FoldedLightCurve(LightCurve):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def phase(self):
|
||||||
|
"""Alias for `LightCurve.time`."""
|
||||||
|
return self.time
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cycle(self):
|
||||||
|
cycle_epoch_start = self.epoch_time - self.period / 2
|
||||||
|
result = np.asarray(np.floor(((self.time_original - cycle_epoch_start) / self.period).value), dtype=int)
|
||||||
|
result = result - result.min()
|
||||||
|
return result
|
||||||
|
|
||||||
|
@property
|
||||||
|
def odd_mask(self):
|
||||||
|
return self.cycle % 2 == 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def even_mask(self):
|
||||||
|
return ~self.odd_mask
|
||||||
|
|
||||||
|
def _set_xlabel(self, kwargs):
|
||||||
|
if "xlabel" not in kwargs:
|
||||||
|
kwargs["xlabel"] = "Phase"
|
||||||
|
if isinstance(self.time, TimeDelta):
|
||||||
|
kwargs["xlabel"] += f" [{self.time.format.upper()}]"
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def plot(self, **kwargs):
|
||||||
|
kwargs = self._set_xlabel(kwargs)
|
||||||
|
return super(FoldedLightCurve, self).plot(**kwargs)
|
||||||
|
|
||||||
|
def scatter(self, **kwargs):
|
||||||
|
kwargs = self._set_xlabel(kwargs)
|
||||||
|
return super(FoldedLightCurve, self).scatter(**kwargs)
|
||||||
|
|
||||||
|
def errorbar(self, **kwargs):
|
||||||
|
kwargs = self._set_xlabel(kwargs)
|
||||||
|
return super(FoldedLightCurve, self).errorbar(**kwargs)
|
||||||
|
|
||||||
|
def plot_river(self, **kwargs):
|
||||||
|
ax = super(FoldedLightCurve, self).plot_river(
|
||||||
|
period=self.period, epoch_time=self.epoch_time, **kwargs
|
||||||
|
)
|
||||||
|
return ax
|
||||||
|
|
||||||
class KeplerLightCurve(LightCurve):
|
class KeplerLightCurve(LightCurve):
|
||||||
"""Subclass of :class:`LightCurve <lightkurve.lightcurve.LightCurve>`
|
"""Subclass of :class:`LightCurve <lightkurve.lightcurve.LightCurve>`
|
||||||
to represent data from NASA's Kepler and K2 mission."""
|
to represent data from NASA's Kepler and K2 mission."""
|
||||||
@@ -1418,3 +1619,5 @@ try:
|
|||||||
except registry.IORegistryError as exc:
|
except registry.IORegistryError as exc:
|
||||||
print(exc)
|
print(exc)
|
||||||
pass # necessary to enable autoreload during debugging
|
pass # necessary to enable autoreload during debugging
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user