7.1. The TimeSeries type#
The ktk.TimeSeries type is largely inspired by Matlab’s timeseries
and tscollection
. Every TimeSeries contains time, data, events and metadata.
7.1.1. Time and data#
A TimeSeries in its simplest form contains a time attribute and at least one data series. For example:
import kineticstoolkit.lab as ktk
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
ts = ktk.TimeSeries() # Create an empty TimeSeries
ts.time = np.arange(0, 10, 0.1) # Assign time
ts.data["Sinus"] = np.sin(ts.time) # Add a data series
ts.data["Cosinus"] = np.cos(ts.time) # Add another data series
ts.data["SquareRoot"] = np.sqrt(ts.time) # Add yet another data series
ts
TimeSeries with attributes:
time: <array of shape (100,)>
data: <dict with 3 entries>
time_info: {'Unit': 's'}
data_info: {}
events: []
We can also add data to a TimeSeries using its add_data method. This method checks that each data series has the same number of samples, whereas assigning it directly to data
(as above) does not perform such verification.
ts = ktk.TimeSeries() # Create an empty TimeSeries
ts.time = np.arange(0, 10, 0.1) # Assign time
ts = ts.add_data("Sinus", np.sin(ts.time)) # Add a data series
ts = ts.add_data("Cosinus", np.cos(ts.time)) # Add another data series
ts = ts.add_data("SquareRoot", np.sqrt(ts.time)) # Add yet another data series
ts
TimeSeries with attributes:
time: <array of shape (100,)>
data: <dict with 3 entries>
time_info: {'Unit': 's'}
data_info: {}
events: []
To see the TimeSeries data:
ts.data
{
'Sinus': <array of shape (100,)>
'Cosinus': <array of shape (100,)>
'SquareRoot': <array of shape (100,)>
}
TimeSeries can be plotted directly using Matplotlib, and we can also specify which of the series to plot.
plt.subplot(1, 3, 1)
ts.plot()
plt.subplot(1, 3, 2)
ts.plot("Cosinus")
plt.subplot(1, 3, 3)
ts.plot(["Sinus", "Cosinus"])
plt.tight_layout()
A TimeSeries can also contain multidimensional data, as long as the first dimension corresponds to time. For instance, this dataset of wheelchair propulsion kinetics expresses forces and moments as Nx4 series of vectors:
ts = ktk.load(ktk.doc.download("kinetics_wheelchair_propulsion.ktk.zip"))
ts.data
{
'Forces': <array of shape (5000, 4)>
'Moments': <array of shape (5000, 4)>
}
ts.plot()
7.1.2. Events#
In the figure above, we see that the TimeSeries contains cyclic data. These cycles could be delimited using events. There are several ways to edit the events of a TimeSeries, that will be presented later in section Event management. For now, we will add the events manually using ktk.TimeSeries.add_event:
ts = ts.add_event(8.56, "push")
ts = ts.add_event(9.93, "recovery")
ts = ts.add_event(10.50, "push")
ts = ts.add_event(11.12, "recovery")
ts = ts.add_event(11.78, "push")
ts = ts.add_event(12.33, "recovery")
ts = ts.add_event(13.39, "push")
ts = ts.add_event(13.88, "recovery")
ts = ts.add_event(14.86, "push")
ts = ts.add_event(15.30, "recovery")
These 10 events are now added to the TimeSeries’ list of events:
ts.events
[TimeSeriesEvent(time=8.56, name='push'),
TimeSeriesEvent(time=9.93, name='recovery'),
TimeSeriesEvent(time=10.5, name='push'),
TimeSeriesEvent(time=11.12, name='recovery'),
TimeSeriesEvent(time=11.78, name='push'),
TimeSeriesEvent(time=12.33, name='recovery'),
TimeSeriesEvent(time=13.39, name='push'),
TimeSeriesEvent(time=13.88, name='recovery'),
TimeSeriesEvent(time=14.86, name='push'),
TimeSeriesEvent(time=15.3, name='recovery')]
If we plot again the TimeSeries, we can see the added events.
ts.plot()
7.1.3. Metadata#
The TimeSeries’ time_info
and data_info
attributes are dictionaries that associate information to time and data. By default, time_info
includes the “Unit” key, which corresponds to “s”. Any other time information can be added by adding new keys to time_info
.
ts.time_info
{
'Unit': 's'
}
Similarly, the data_info
attribute is a dictionary that associates information to data. You may use the ktk.TimeSeries.add_data_info and ktk.TimeSeries.remove_data_info methods to ease the management of data_info
:
ts = ts.add_data_info("Forces", "Unit", "N")
ts = ts.add_data_info("Moments", "Unit", "Nm")
ts.data_info
{
'Forces': {'Unit': 'N'}
'Moments': {'Unit': 'Nm'}
}
Unless explicitly mentioned, metadata is not used for calculation and is strictly optional. Some functions however read metadata: for example, the ktk.TimeSeries.plot method looks for possible “Unit” metadata and prints it on the y axis; and the ktk.Player class looks for possible “Color” metadata to set the colour of 3D points.
ts.plot()
7.1.4. Converting variables to TimeSeries#
We can convert a list, a NumPy array, a Pandas Series or a Pandas DataFrame to a TimeSeries, using this form:
example_list = [1, 2, 3, 4, 5]
example_array = np.array([1, 2, 3, 4, 5])
example_series = pd.Series([1, 2, 3, 4, 5])
example_dataframe = pd.DataFrame([[1, 2], [3, 4], [5, 6], [7, 8]], columns=["x", "y"])
7.1.4.1. List to TimeSeries#
ktk.TimeSeries(example_list)
TimeSeries with attributes:
time: array([0., 1., 2., 3., 4.])
data: {'data': array([1, 2, 3, 4, 5])}
time_info: {'Unit': 's'}
data_info: {}
events: []
7.1.4.2. Array to TimeSeries#
ktk.TimeSeries(example_array)
TimeSeries with attributes:
time: array([0., 1., 2., 3., 4.])
data: {'data': array([1, 2, 3, 4, 5])}
time_info: {'Unit': 's'}
data_info: {}
events: []
7.1.4.3. Series to TimeSeries#
ktk.TimeSeries(example_series)
TimeSeries with attributes:
time: array([0., 1., 2., 3., 4.])
data: {'data': array([1, 2, 3, 4, 5])}
time_info: {'Unit': 's'}
data_info: {}
events: []
7.1.4.4. DataFrame to TimeSeries#
ktk.TimeSeries(example_dataframe)
TimeSeries with attributes:
time: array([0, 1, 2, 3])
data: {'x': array([1, 3, 5, 7]), 'y': array([2, 4, 6, 8])}
time_info: {'Unit': 's'}
data_info: {}
events: []