Operators
When building a Bonsai program, you chain together reactive operators to create new observable sequences. There are many different operators, which can create all kinds of observable sequences. These operators can be roughly grouped into different categories, depending on their shared characteristics.
Category |
Description |
 |
generate event streams from devices or files |
 |
convert or process individual data items |
 |
filter data items matching some specific condition |
 |
save data or trigger external outputs |
 |
manage control flow or synchronize parallel inputs |
Source
Sources create sequences that generate notifications spontaneously. This means that you can place these nodes without connecting them to any input. Every Bonsai program will contain at least one source. Usually sources represent streams of data which are acquired from devices or files, such as cameras, microphones, accelerometers, WAV files, network sockets, touchpads, etc.
Note
Even though all sources can be placed independently, sometimes you can still connect an input to them. For example, if you place a FileCapture
source by itself, it will playback all frames of the movie at the specified frame rate. However, if you connect it to an input, the next frame will be decoded only when a new notification arrives, allowing you to precisely control video playback.
Transforms apply an operation to individual data items in a sequence. They always take exactly one input sequence, and generate another sequence which has the same number of elements as the input, but where each item has been modified according to the function specified by the transform.
In other words, all transforms have a similar style of marble diagram:

Every transform will always produce exactly one item for every notification generated by the input sequence. Each item that is produced will be the result of applying the transform function on the elements of the input sequence, and is sent out immediately whenever a new notification is received. When the input sequence terminates successfully (or exceptionally), the transformed sequence also terminates.
The only distinction between different transforms will be in the exact function that is applied to each element (e.g., Grayscale
will convert a sequence of color images to a sequence of grayscale images, while FindContours
will convert a sequence of binary images into a sequence of contours).
Condition
Condition operators apply a filter on individual data items in a sequence. Similar to transforms, they always take exactly one input sequence, and generate another sequence where the only emitted elements are items from the original sequence that match the condition criteria.

The condition function is applied to individual items immediately whenever a new notification is received from the input sequence, and valid items are sent out as soon as they are found to match the criteria. When the input sequence terminates successfully (or exceptionally), the filtered sequence also terminates.
Note
The Condition
operator allows you to specify arbitrary matching criteria using a node group. The input to the nested node group is the unfiltered sequence, and the output must be a sequence of elements of type bool
, i.e. logical values indicating true
or false
depending on whether the current item is considered to match the criteria.
Sink
Whenever you need to save data into a file, trigger an external output, move a motor, or otherwise generate some kind of side effect with the data processed in Bonsai, you probably need to use a sink operator. Similar to transforms and conditions, sinks also apply a function to every individual element of an observable sequence. However, the application of the function will not modify or filter the input items in any way, which means the output sequence generated by a sink is identical to the input sequence.
For this reason, all sinks also share a very similar style of marble diagram:

Because the output sequence of a sink is exactly the same as the input sequence, sinks can always be placed at any point of the workflow without breaking existing behaviour.
Note
You can chain multiple sinks sequentially as long as the input is compatible. This can be very convenient when you need to run multiple side effects on a single data stream. A common application is to log data into a file while simultaneously transmitting it to an external device.
Combinator
Although a lot can be done with the right sequence of sources, transforms and sinks, there are many other operators which allow you to express more complex combinations of observables. These operators are grouped together under the Combinator
category, but their behaviour can be extremely diverse.
Combinators can be used to merge data from multiple sources; control when observable sequences start and stop; or even to create entirely new sequences dynamically. Together, they provide an incredibly flexible toolkit to manipulate asynchronous data streams.
Core Reactive Operators
Bonsai includes a set of core reactive operators that are commonly used across workflows. To locate them, search for Reactive
in the Toolbox Panel
. The tables below categorize these operators and provide brief descriptions of their functionality.
Single-Sequence Operators
Operators that generate or extract numerical values from a sequence.
Name |
Description |
Accumulate |
Computes the cumulative sum of a sequence |
Average |
Computes the numerical average of a sequence |
Count |
Count the number of elements in a sequence |
ElementIndex |
Extracts the zero-based index of elements in a sequence |
Max |
Computes the maximum element in a sequence |
MaxBy |
Computes the element with the maximum key value in a sequence |
Min |
Computes the minimum element in a sequence |
MinBy |
Computes the element with the minimum key value in a sequence |
Range |
Generates a sequence of integer numbers within a specified range |
Sum |
Computes the sum of a sequence |
Note
Some of these operators have package-specific variants especially designed to handle unique data types (for instance, Dsp.Average
).
Note
More quantitative operators are available in the Numerics
package.
Operators that use timing information to generate, manipulate, and sample sequences.
Name |
Description |
CombineTimestamp |
Converts element-timestamp pairs of a sequence into proper timestamped elements |
Delay |
Delays the notifications of a sequence by the specified time interval |
DelaySubscription |
Time-shifts the sequence by delaying the subscription by the specified time interval |
GateInterval |
Allows a single element from the first sequence to pass through every time the specified time interval elapses |
SampleInterval |
Samples the latest element from the sequence whenever the specified time interval elapses |
Throttle |
Ignores elements from a sequence which are followed by another element before the specified duration elapses |
Timer |
Generates a sequence that periodically produces a value after the specified initial relative due time has elapsed |
TimeInterval |
Records the time interval between consecutive elements produced by a sequence |
Timestamp |
Records the timestamp for each element produced by a sequence |
Operators that rerun sequences.
Name |
Description |
Repeat |
Repeats a sequence indefinitely |
RepeatCount |
Repeats a sequence a specified number of times |
Operators that filter or select elements from a sequence.
Name |
Description |
Condition |
Filters the elements of a sequence according to a condition specified by the encapsulated workflow |
Distinct |
Returns a sequence containing only distinct elements |
DistinctBy |
Returns a sequence containing only elements which are distinct according to the specified key |
DistinctUntilChanged |
Returns a sequence containing only distinct contiguous elements |
DistinctUntilChangedBy |
Returns a sequence containing only distinct contiguous elements according to the specified key |
First |
Returns the first element of a sequence |
FirstOrDefault |
Returns the first element of a sequence, or a default value if no such element exists |
IgnoreElements |
Ignores all elements in a sequence leaving only the termination messages |
Last |
Returns the last element of a sequence |
LastOrDefault |
Returns the last element of a sequence, or a default value if no such element exists |
Skip |
Bypasses the specified number of elements at the start of a sequence and returns the remaining elements |
SkipLast |
Bypasses the specified number of elements at the end of a sequence |
SkipWhile |
Bypasses elements in a sequence as long as the condition specified by the encapsulated workflow is true |
Slice |
Extracts a range of elements from a sequence |
Take |
Returns the specified number of contiguous elements from the start of a sequence |
TakeLast |
Returns a specified number of contiguous elements from the end of a sequence |
TakeWhile |
Returns elements from a sequence as long as the condition specified by the encapsulated workflow is true |
Operators that group elements of a sequence into collections or new sequences.
Name |
Description |
BufferCount |
Projects each element of the sequence into zero or more buffers based on element count information |
BufferTime |
Projects each element of the sequence into zero or more buffers based on timing information |
GroupBy |
Creates new sequences by grouping the elements of a sequence according to the specified key |
WindowCount |
Projects each element of a sequence into zero or more windows based on element count information |
WindowTime |
Projects each element of a sequence into zero or more windows based on timing information |
Operators that sort elements within each collection of a sequence.
Name |
Description |
OrderBy |
Sorts the elements of all the collections in a sequence in ascending order according to the specified key |
OrderByDescending |
Sorts the elements of all the collections in a sequence in descending order according to the specified key |
ThenBy |
Applies an additional ascending sort to ordered collections produced by any of the sorting operators |
ThenByDescending |
Applies an additional descending sort to ordered collections produced by any of the sorting operators |
Operators that generate new sequences based on an encapsulated workflow.
Name |
Description |
CreateObservable |
Creates higher-order sequences specified by the encapsulated workflow |
Defer |
Creates a new sequence for each subscription using the encapsulated workflow |
SelectMany |
Merges higher-order sequences generated from the encapsulated workflow |
Scan |
Accumulates the values of a sequence using the encapsulated workflow |
Operators that transform sequences into various object types.
Name |
Description |
ToArray |
Creates an array containing every element in the sequence |
ToDictionary |
Creates a dictionary from a sequence according to the specified key and element selector |
ToList |
Creates a list containing every element in the sequence |
ToLookup |
Creates a lookup from a sequence according to the specified key and element selector |
Note
These operators convert whole sequences into different types. For element-wise type conversion, check out the ExpressionTransform operator.
Operators that allow reusing and sharing of sequences. See the subjects article for more information.
Name |
Description |
AsyncSubject |
Broadcasts the last value of a sequence to all subscribed and future observers using a shared subject |
BehaviorSubject |
Broadcasts the latest value of a sequence to all subscribed and future observers using a shared subject |
PublishSubject |
Broadcasts the values of a sequence to multiple subscribers using a shared subject |
ReplaySubject |
Replays the values of a sequence to all subscribed and future observers using a shared subject |
ResourceSubject |
Stores and broadcasts the last disposable value of a sequence to all subscribed and future observers |
Operators that check sequences for errors and manage exceptions.
Name |
Description |
IsEmpty |
Checks if a sequence is empty |
Materialize |
Materializes the implicit notifications of a sequence as explicit notification values for debugging/logging purposes |
Dematerialize |
Dematerializes the explicit notification values of a sequence as implicit notifications |
Retry |
Repeats a sequence until it successfully terminates |
RetryCount |
Repeats a sequence the specified number of times or until it successfully terminates |
Timeout |
Raises an error if the next element is not received within the specified timeout duration from the previous element |
Multi-Sequence Operators
Operators that use notifications from one sequence to select elements from another.
Name |
Description |
Gate |
Allows a single element from the first sequence to pass through every time a second sequence emits a notification |
Sample |
Samples elements from the first sequence whenever the second sequence emits a notification. |
SkipUntil |
Returns the elements from the first sequence only after the second sequence emits a notification |
SubscribeWhen |
Subscribes to the first sequence only after the second sequence emits a notification |
TakeUntil |
Returns elements from the first sequence only until the second sequence emits a notification |
Operators that use notifications from one sequence to group elements from another sequence into collections or new sequences.
Name |
Description |
BufferTrigger |
Projects elements of the first sequence into zero or more buffers created when the second sequence emits a notification |
Window |
Projects the first sequence into zero or more windows with boundaries defined by the second sequence |
WindowTrigger |
Projects elements of the first sequence into zero or more windows created when the second sequence emits a notification |
Operators that select which elements from multiple sequences to propagate.
Name |
Description |
Amb |
Propagates the sequence that issues notifications first |
Switch |
Transforms a sequence of sequences into a sequence of values produced only from the most recent sequence |
Operators that merge, concatenate, or pair values from multiple sequences.
Name |
Description |
CombineLatest |
Combines values from the source sequences whenever any of the sequences produces an element |
Concat |
Concatenates any number of sequences as long as the previous sequence terminated successfully |
Merge |
Merges any number of sequences into a single sequence |
WithLatestFrom |
Combines the latest values from the source sequences only when the first sequence produces an element |
Zip |
Combines values from the source sequences whenever all of the sequences have produced an element |
Operators that check multiple sequences for errors and manage exceptions.
Name |
Description |
SequenceEqual |
Determines whether two sequences are equal by comparing the elements pairwise |
Catch |
Continues a sequence that is terminated by an exception with the next sequence |
OnErrorResumeNext |
Concatenates any number of sequences even if any of the sequences terminates exceptionally |