# 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 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 ( or ) 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 is the maximal one, which still fulfills: .

### Questions¶

The follwing 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)]
```