diff --git a/docs/changes/912.bugfix.rst b/docs/changes/912.bugfix.rst new file mode 100644 index 000000000..b6da40447 --- /dev/null +++ b/docs/changes/912.bugfix.rst @@ -0,0 +1 @@ +Fixed the ``tstart`` attribute not updating correctly in the ``stingray.Lightcurve.shift`` method. diff --git a/stingray/lightcurve.py b/stingray/lightcurve.py index c6cff03b6..a8fe5c456 100644 --- a/stingray/lightcurve.py +++ b/stingray/lightcurve.py @@ -8,6 +8,7 @@ import os import logging import warnings +import copy from collections.abc import Iterable import numpy as np @@ -88,6 +89,8 @@ class Lightcurve(StingrayTimeseries): uncertainties and other statistical values appropriately. Default makes no assumptions and keep errors equal to zero. + Stingray currently supports only Poisson error distribution. + All light curve analyses will assume Poisson errors. bg_counts: iterable,`:class:numpy.array` or `:class:List` of floats, optional, default ``None`` A list or array of background counts detected in the background extraction region in each bin corresponding to the bins defined in `time`. @@ -306,7 +309,6 @@ def __init__( dt = 1.0 self.dt = dt - if isinstance(dt, Iterable): warnings.warn( "Some functionalities of Stingray Lightcurve will not work when `dt` is Iterable" @@ -1159,6 +1161,43 @@ def truncate(self, start=0, stop=None, method="index"): return super().truncate(start=start, stop=stop, method=method) + def shift(self, time_shift: float, inplace=False): + """Shift the time and the GTIs by the same amount + + Parameters + ---------- + time_shift: float + The time interval by which the time series will be shifted (in + the same units as the time array in :class:`StingrayTimeseries` + + Other parameters + ---------------- + inplace : bool + If True, overwrite the current time series. Otherwise, return a new one. + + Returns + ------- + ts : ``StingrayTimeseries`` object + The new time series shifted by ``time_shift`` + + """ + if inplace: + ts = self + else: + ts = copy.deepcopy(self) + ts.time = ts._time = np.asanyarray(ts.time) + time_shift # type: ignore + + if isinstance(self.dt, Iterable): + ts.tstart = ts._time[0] - 0.5 * self.dt[0] + else: + ts.tstart = ts._time[0] - 0.5 * self.dt + # Pay attention here: if the GTIs are created dynamically while we + # access the property, + if ts._gti is not None: + ts._gti = np.asanyarray(ts._gti) + time_shift # type: ignore + + return ts + def split(self, min_gap, min_points=1): """ For data with gaps, it can sometimes be useful to be able to split diff --git a/stingray/tests/test_lightcurve.py b/stingray/tests/test_lightcurve.py index 8dc528b2c..f641eb60d 100644 --- a/stingray/tests/test_lightcurve.py +++ b/stingray/tests/test_lightcurve.py @@ -1329,12 +1329,31 @@ def test_shift(self): lc = Lightcurve(times, counts, input_counts=True) lc2 = lc.shift(1) assert np.allclose(lc2.time - 1, times) + assert np.allclose(lc2.tstart - 1, lc.tstart) + + lc1 = Lightcurve(times, counts, input_counts=True) + with pytest.warns( + UserWarning, + match="Some functionalities of Stingray Lightcurve will not work when `dt` is Iterable", + ): + lc2 = Lightcurve( + times, counts, input_counts=True, dt=[1.0] * len(times), skip_checks=True + ) + lc1.shift(1, inplace=True) + lc2.shift(1, inplace=True) + assert np.allclose(lc1.time - 1, times) + assert np.allclose(lc1.tstart - 1, lc.tstart) + assert np.allclose(lc2.time - 1, times) + assert np.allclose(lc2.tstart - 1, lc.tstart) + lc2 = lc.shift(-1) assert np.allclose(lc2.time + 1, times) + assert np.allclose(lc2.tstart + 1, lc.tstart) assert np.allclose(lc2.counts, lc.counts) assert np.allclose(lc2.countrate, lc.countrate) lc = Lightcurve(times, counts, input_counts=False) lc2 = lc.shift(1) + assert np.allclose(lc2.tstart - 1, lc.tstart) assert np.allclose(lc2.counts, lc.counts) assert np.allclose(lc2.countrate, lc.countrate)