Skip to content

litmus.lightcurve

Bases: object

A wrapper class for lightcurves. Construct /w array-like inputs for time, signal and error (optional) like: lightcurve(T, Y, E) or: lightcurve(T, Y) Which yields E=0 for all {T,Y}

Supports array-like addition and float-like addition / multiplication

Source code in litmus/lightcurve.py
def __init__(self, T, Y, E=None):
    self.T = np.array(T, dtype=np.float64)
    self.Y = np.array(Y, dtype=np.float64)
    if E is None:
        self.E = np.zeros_like(T)
    else:
        self.E = E

    self._data = np.vstack(self.values()).T

    self._norm_mean, self._norm_amp = 0.0, 1.0
    self.normalized = False

T = np.array(T, dtype=np.float64) instance-attribute

Y = np.array(Y, dtype=np.float64) instance-attribute

E = np.zeros_like(T) instance-attribute

normalized = False instance-attribute

keys() -> [str, str, str]

Returns the string-like names of the lightcurve's attributes

Source code in litmus/lightcurve.py
def keys(self) -> [str, str, str]:
    """
    Returns the string-like names of the lightcurve's attributes
    """
    return ["T", "Y", "E"]

values() -> (_types.ArrayN, _types.ArrayN, _types.ArrayN)

Returns the lightcurves' value series' in the order of keys

Source code in litmus/lightcurve.py
def values(self) -> (_types.ArrayN, _types.ArrayN, _types.ArrayN):
    """
    Returns the lightcurves' value series' in the order of keys
    """
    return [self[key] for key in self.keys()]

normalize() -> _types.Self

Esimates the mean and amplitude of the lighturve assuming uncorrelated measurements Returns a lightcurve object with this normalization

Source code in litmus/lightcurve.py
def normalize(self) -> _types.Self:
    """
    Esimates the mean and amplitude of the lighturve assuming uncorrelated measurements
    Returns a lightcurve object with this normalization
    """

    if self.normalized: return self

    # Check if have errorbars
    no_errs = False
    E = self.E
    if max(E) == 0:
        no_errs = True
        E = np.ones_like(self.E)

    # Get initial guess assuming no scatter
    w = E ** -2
    mean0 = np.average(self.Y, weights=w)
    var0 = np.average((self.Y - mean0) ** 2, weights=w)

    if no_errs:
        meanbest, varbest = mean0, var0
    else:
        L = lambda X: ((self.Y - X[0]) ** 2 / (self.E ** 2 + X[1]) + np.log(self.E ** 2 + X[1])).sum()
        meanbest, varbest = optimize.minimize(L, np.array([mean0, var0]), method='Nelder-Mead').x

    # Make and return copy
    out = copy(self)
    out -= meanbest
    out /= np.sqrt(varbest)

    # If any errors, revert to simple estiamte
    if np.any(np.isnan(out._data)):
        meanbest, varbest = mean0, var0
        out = copy(self)
        out -= meanbest
        out /= np.sqrt(varbest)

    # Store normalizing values for later
    out._norm_mean = meanbest
    out._norm_amp = np.sqrt(varbest)

    out.normalized = True

    return out

unnormalize() -> _types.Self

Reverses the effects of lightcurve.normalize(). Returns a lightcurve object with mean and amplitude prior to normalize()

Source code in litmus/lightcurve.py
def unnormalize(self) -> _types.Self:
    """
    Reverses the effects of lightcurve.normalize().
    Returns a lightcurve object with mean and amplitude prior to normalize()
    """
    out = copy(self)
    out *= self._norm_amp
    out += self._norm_mean
    out._norm_amp = 1.0
    out._norm_mean = 0.0
    out.normalized = False
    return out

delayed_copy(lag=0.0, Tmin=None, Tmax=None) -> _types.Self

Returns a copy subsampled to only datapoints in the domain T in [Tmin,Tmax] and offset by lag

Source code in litmus/lightcurve.py
def delayed_copy(self, lag=0.0, Tmin=None, Tmax=None) -> _types.Self:
    """
    Returns a copy subsampled to only datapoints in the domain T in [Tmin,Tmax] and offset by lag
    """
    if Tmin is None: Tmin = self.T.min()
    if Tmax is None: Tmax = self.T.max()
    I = np.where((self.T + lag > Tmin) * (self.T + lag < Tmax))[0]

    return (lightcurve(T=self.T[I] + lag,
                       Y=self.Y[I],
                       E=self.E[I]
                       ))

trimmed_copy(Tmin=None, Tmax=None) -> _types.Self

Returns a copy subsampled to only datapoints in the domain T in [Tmin,Tmax]

Source code in litmus/lightcurve.py
def trimmed_copy(self, Tmin=None, Tmax=None) -> _types.Self:
    """
    Returns a copy subsampled to only datapoints in the domain T in [Tmin,Tmax]
    """
    return self.delayed_copy(0, Tmin, Tmax)

concatenate(other)

Source code in litmus/lightcurve.py
def concatenate(self, other):
    T1, T2 = self.T, other.T
    Y1, Y2 = self.Y, other.Y
    E1, E2 = self.E, other.E
    T, Y, E = np.concatenate([T1, T2]), np.concatenate([Y1, Y2]), np.concatenate([E1, E2])
    return lightcurve(T, Y, E)

plot(axis=None, show=True, **kwargs) -> None

Plots an errorbar series to a matplotlib axis. If show=True, will plt.show() after plotting. If axis is None, will create a new figure. Pass in any plotting kwargs for plt.errorbar at **kwargs

Source code in litmus/lightcurve.py
def plot(self, axis=None, show=True, **kwargs) -> None:
    """
    Plots an errorbar series to a matplotlib axis.
    If show=True, will plt.show() after plotting.
    If axis is None, will create a new figure.
    Pass in any plotting kwargs for plt.errorbar at **kwargs
    """
    if axis is None:
        plt.figure()
        axis = plt.gca()
        axis.set_xlabel("T")
        axis.set_ylabel("Y")
    axis.errorbar(self.T, self.Y, self.E, fmt='none', **kwargs)

    if show: plt.show()

copy()

Source code in litmus/lightcurve.py
def copy(self):
    return copy(self)