Series and Frames
Learn how to use series and frames in the Python client.
Series and frames are the two fundamental structures used for working with channel data
in Synnax. This guide will walk you through how to use the Series
and Frame
classes
exposed by the Python client.
Series
A series is a strongly typed array of data samples. It can contain any data you want it to, but in the context of Synnax it almost always represents a set of contiguous samples from a single channel.
Constructing a Series
There are many ways to construct a series:
import synnax as sy
import numpy as np
# Construct a series from a list of samples. In this case, the series
# will automatically be assumed to be of type int64.
series = sy.Series([1, 2, 3, 4, 5])
# We can also manually specify the type of the series
series = sy.Series([1, 2, 3, 4, 5], data_type=sy.DataType.INT32)
# Construct a series from a numpy array. The type of the series
# will be inferred from the numpy array.
series = sy.Series(np.array([1, 2, 3, 4, 5], dtype=np.int64))
# Construct a series from a list of strings. In this case,
# the series will automatically be assumed to be of type string.
series = sy.Series(["apple", "banana", "cherry"])
# Construct a series from dictionaries. In this case, the series
# will automatically be assumed to be of type json.
series = sy.Series([{"a": 1}, {"b": 2}, {"c": 3}])
Interop with Numpy
The Series
class is designed to be directly compatible with numpy, and supports all
of the operations possible on a numpy array without needing to convert back and forth.
Here’s a simple example:
import synnax as sy
import numpy as np
series = sy.Series([1, 2, 3, 4, 5])
# You can use numpy functions directly on a series
print(np.mean(series))
This means that it’s also possible to pass a series directly into libraries like
matplotlib
:
import synnax as sy
import matplotlib.pyplot as plt
x_data = sy.Series([1, 2, 3, 4, 5])
y_data = sy.Series([1, 4, 9, 16, 25])
plt.plot(x_data, y_data)
plt.show()
If you’d like to convert a series to a numpy array, you can do so with the to_numpy
function or by simply passing the series to np.array
:
import synnax as sy
series = sy.Series([1, 2, 3, 4, 5])
# Convert the series to a numpy array
numpy_array = series.to_numpy()
# Convert the series to a numpy array using np.array
numpy_array = np.array(series)
The Time Range Property
Whenever you read a series from Synnax, it will have a time_range
property
that represents the time range occupied by the samples in the Series. This
method can be useful for getting a high-level understanding of when the samples
were recorded without needing to query an index channel.
The start
field represents the timestamp for the first sample, and the end
field represents a timestamp just after the last sample (start-inclusive,
end-exclusive).
It’s also easy to define a time range when constructing your own series:
import synnax as sy
start = sy.TimeStamp.now()
series = sy.Series(
[1, 2, 3, 4, 5],
time_range=sy.TimeRange(
start=start,
end=start + sy.TimeSpan.SECOND * 6,
)
)
Frames
A frame is a collection of series from multiple channels. Frames are returned by methods like:
- The
read
method on the client (client.read
) - The
read
method of aStreamer
instance (client.open_streamer
) - The
value
property of anIterator
instance (client.open_iterator
)
Constructing a Frame
A frame maps the key or name of a channel to one or more series. Here are a few examples of how to construct a frame:
import synnax as sy
# Construct a frame for the given channel names.
frame = sy.Frame({
"channel1": sy.Series([1, 2, 3, 4, 5]),
"channel2": sy.Series([5, 4, 3, 2, 1]),
"channel3": sy.Series([1, 1, 1, 1, 1]),
})
# Construct a frame from individual samples.
frame = sy.Frame({
"channel1": 1,
"channel2": 2,
"channel3": 3,
})
Accessing Frame Data
Using the dictionary interface
Frames can be accessed like dictionaries:
import synnax as sy
data = frame["channel1"]
The data
variable will be an instance of a MultiSeries
object, which is a
special type of series that wraps multiple Series
instances, but behaves
pretty much exactly like a single series:
import synnax as sy
frame = sy.Frame({
"channel1": [sy.Series([1, 2, 3, 4, 5]), sy.Series([6, 7, 8, 9, 10])]
"channel2": sy.Series([1, 2, 3]),
})
# Access the first series in the "channel1" key
data: sy.MultiSeries = frame["channel1"]
print(data[0]) # 1
print(data[-1]) # 10