Source code for exoctk.lightcurve_fitting.lightcurve
"""Base and child classes to handle light curve fitting
Author: Joe Filippazzo
Email: jfilippazzo@stsci.edu
"""
import numpy as np
import pandas as pd
from bokeh.plotting import figure, show
from .models import Model, CompositeModel
from .fitters import lmfitter
from ..utils import COLORS
[docs]class LightCurveFitter:
def __init__(self, time, flux, model):
"""Fit the model to the flux cube
Parameters
----------
time:
1D or 2D time axes
flux:
2D flux
"""
self.flux = np.ones(100)
self.time = np.arange(100)
self.results = pd.DataFrame(names=('fit_number', 'wavelength', 'P',
'Tc', 'a/Rs', 'b', 'd', 'ldcs',
'e', 'w', 'model_name', 'chi2'))
[docs] def run(self):
"""Run the model fits"""
pass
# Method to return sliced results table
[docs] def master_slicer(self, value, param_name='wavelength'):
return self.results.iloc[self.results[param_name] == value]
[docs]class LightCurve(Model):
def __init__(self, time, flux, unc=None, parameters=None, units='MJD', name='My Light Curve'):
"""
A class to store the actual light curve
Parameters
----------
time: sequence
The time axis in days, [MJD or BJD]
flux: sequence
The flux in electrons (not ADU)
unc: sequence
The uncertainty on the flux
parameters: str, object (optional)
The orbital parameters of the star/planet system,
may be a path to a JSON file or a parameter object
units: str
The time units
name: str
A name for the object
"""
# Initialize the model
super().__init__()
# Check data
if len(time) != len(flux):
raise ValueError('Time and flux axes must be the same length.')
# Set the data arrays
if unc is not None:
if len(unc) != len(time):
raise ValueError('Time and unc axes must be the same length.')
self.unc = unc
else:
self.unc = np.array([np.nan]*len(self.time))
# Set the time and flux axes
self.time = time
self.flux = flux
# Set the units
self.units = units
self.name = name
# Place to save the fit results
self.results = []
[docs] def fit(self, model, fitter='lmfit', **kwargs):
"""Fit the model to the lightcurve
Parameters
----------
model: ExoCTK.lightcurve_fitter.models.Model
The model to fit to the data
fitter: str
The name of the fitter to use
"""
# Empty default fit
fit_model = None
# Make sure the model is a CompositeModel
if not isinstance(model, type(CompositeModel)):
model = CompositeModel([model])
if fitter == 'lmfit':
# Run the fit
fit_model = lmfitter(self.time, self.flux, model, self.unc, **kwargs)
else:
raise ValueError("{} is not a valid fitter.".format(fitter))
# Store it
if fit_model is not None:
self.results.append(fit_model)
[docs] def plot(self, fits=True, draw=True):
"""Plot the light curve with all available fits
Parameters
----------
fits: bool
Plot the fit models
draw: bool
Show the figure, else return it
Returns
-------
bokeh.plotting.figure
The figure
"""
# Make the figure
fig = figure(width=800, height=400)
# Draw the data
fig.circle(self.time, self.flux, legend=self.name)
# Plot fit models
if fits and len(self.results) > 0:
for model in self.results:
model.plot(self.time, fig=fig, color=next(COLORS))
# Format axes
fig.xaxis.axis_label = str(self.units)
fig.yaxis.axis_label = 'Flux'
# Draw or return
if draw:
show(fig)
else:
return fig
[docs] def reset(self):
"""Reset the results"""
self.results = []