Time-series access

Since one dimension of time-series data is associated with time, there is a natural way to index into time-series data using time objects as indices. For the data classes (Time-series) an indexing operation performed with a single time-point (a single-element TimeArray or a TimeArray with more than one element) should result in returning the data at that time-point - that is, removal of the time-dimension from the data.

The base-classes representing time (Time) serve as natural intermediaries in this process, by providing the integer index of a particular time-point (or returning an array of integers, as the case may be, see below). Therefore, these classes should include a method which performs this conversion, index_at(). This function should accept as parameter a TimeArray and return integers corresponding to the location of that time-point in the different types of time classes.

Access into Time classes

EventArray

ev.index_at() returns the indices of the values in the array that are closest to t. That is, it returns i, such that \(|(t-t_i)|\) is the minimal.

Potentially, an optional ‘tolerance’ argument can be implemented, specifying a maximal time difference between the index time and the returned time.

NonUniformTime

As above, nut.index_at() also returns the indices in the array that are closest to t. Since NonUniformTime is ordered, this should give you either the index below or the index above the time-point you provide as input, depending on what interval (\(|t-t_i|\) or \(|t-t_{i+1}|\)) is smaller.

UniformTime

ut.index_at() returns the indices of the values in the array that are the largest time values, smaller thatn the input values t. That is, it returns i for which \(t_i\) is the maximal one, which still fulfills: \(t_i<t\).

Questions

The following questions apply to all three cases:

  • what happens when the t is smaller than the smallest entry in the array return None?
  • what happens when t is larget than the last entry in the time array? return None?

at()

This function extracts the value of the time array, which corresponds to the output of index_at() with an input t.

That is, for an instance T of one of the time classes, this function will return:

T.time[T.index_at(t)]

Indexing into data time-series objects

Indexing with time

The above function index_at() serves as the basis for the implementation of the function at() for the time-series data objects. This function returns the part of the data in UniformTimeSeries.data (or the equivalent data structure in EventSeries and NonUniformTimeSeries) that corresponds to the times provided.

Importantly, the result of indexing into a time-series data object using a time object is always again either an instance of the same time-series data class or an instance of a vanilla nd-array. The latter case only occurs, when a single time point is used to index into the time-series data and is analogous to indexing with a single integer into an nd-array. Conversion between different time-series classes can occur if the indexing time-points are non-uniform (for conversion between UniformTimeSeries and NonUniformTimeSeries) or if the time-points are not ordered (for conversion from UniformTimeSeries or from NonUniformTimeSeries to EventSeries).

Currently, the plan is to implement the indexing operation using the method at() and only later to map the method ts.__getitem__() to the function ts.at(). For now, we not that using the function ts.at() directly is more flexible since it allows to use additional keyword arguments, so, for now, it is unclear what to set as the default behavior for at(), which will be executed by __getitem__().

The function during() will receive as input a TimeInterval objects and will return the data corresponding to the interval, while dealing appropriately with the TI.t_step (see Interval object for details). How is this done? For an object of class UniformTimeSeries, access using intervals, will give you back a uniform time-series objects with the time being of length of TI.t_start - TI.t_stop and with the TS.t0 offset by the TimeInterval’s TI.t_step.

Indexing with integers

In parallel to the access with time-points, described above, we would like to implement indexing the time-series classes directly using integer indices and ordinary slices (with integer start, stop, and step). This should have the same effect as indexing the underlying nd-array using the same indices and slices, such that:

T.at(T.time.index_at(i)) = T[i] = T.data[...,i]
T.time.at(i) = T.time[i] = T.time.asarray()[i]

In order to make the above code more compact, would be another reason to implement the the time dimension as the first dimension (not last, see Time-series): this would allow to rewrite the above:

T.at(i) = T[i] = T.data[i]

Every time-series data (and time) object would also implements a method T.slice_at() that given a TimeInterval object TI (see Interval object) returns an integer slice slice(i,j) suitable for indexing both into the nd-array T.data and into T.time:

 T.interval2slice(TI) = slice(T.time2index(TI.t_start),
 T.time2index(TI.t_stop))

data_slice = T.data[...,T.slice_at(TI)]
time_slice = T.time[T.slice_at(TI)]