Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
f44ed02
Add examples for reactive quantitative operators
banchan86 Mar 22, 2025
5ee27a8
Replace key presses and mouse inputs with core inputs
banchan86 Mar 25, 2025
100cacb
add merge and combinelatest examples
banchan86 Apr 1, 2025
ac2c1ed
Modify examples to repeat, improve grammar and clarity
banchan86 Apr 1, 2025
67b4078
Add zip example
banchan86 Apr 2, 2025
d21d1f7
Add reactive examples and improve example presentation
banchan86 Apr 3, 2025
d8e5611
Add subheadings for application examples
banchan86 Apr 10, 2025
107ea07
Update section titles and examples for Zip operator
banchan86 Apr 19, 2025
27951bf
Add Sample example, edit Zip example description
banchan86 Apr 19, 2025
41b318e
Edit Accumulate example description for clarity
banchan86 Apr 19, 2025
ef4051f
Add Gate example
banchan86 Apr 20, 2025
23207ec
Edit alternatives section for grammar and clarity
banchan86 Apr 20, 2025
b512bf9
Add SkipUntil and TakeUntil examples, edit titles for grammar
banchan86 Apr 21, 2025
547b6b7
Add SubscribeWhen example and warning
banchan86 Apr 21, 2025
221cd67
Add SubscribeWhen svg and clarify SkipUntil warning
banchan86 Apr 21, 2025
262b133
Remove redundant lines from end of markdown snippets
banchan86 Apr 21, 2025
e944fc2
Replace Take(1) operator with First in examples
banchan86 Apr 21, 2025
6ea5057
Add First, Last, Take, TakeLast examples
banchan86 Apr 21, 2025
073fb24
Add examples for OrDefault variants of First & Last operators
banchan86 May 16, 2025
0a2b868
Add example svgs for OrDefault variants of First & Last operators
banchan86 May 16, 2025
1a1a032
Add Skip and SkipLast examples
banchan86 May 16, 2025
0da0295
Add Slice examples
banchan86 May 16, 2025
10bff54
Add Distinct examples
banchan86 May 17, 2025
92e1c01
Update quantitative operator examples for Bonsai 2.9.0
banchan86 Jun 12, 2025
170d306
Add note on package dependency for average application example
banchan86 Jun 27, 2025
b11827e
Update combine operator examples for bonsai 2.9
banchan86 Jul 1, 2025
9fbadc4
Update dynamic filter operator examples for Bonsai 2.9
banchan86 Jul 1, 2025
5972e13
Update filter operator examples for Bonsai 2.9
banchan86 Jul 1, 2025
7982cd0
Move VisualizerWindow to avoid obscuring workflow
banchan86 Jul 15, 2025
07e0f9e
Add Condition and DistincUntilChanged examples
banchan86 Jul 15, 2025
1e4466b
Add temporal reactive operators
banchan86 Jul 17, 2025
5131d27
Add Delay and DelaySubscription examples
banchan86 Jul 22, 2025
804cabf
Update CombineTimestamp docs to CreateTimestamped
banchan86 Jul 22, 2025
27aab33
Add Repeat and RepeatCount examples
banchan86 Aug 23, 2025
641b244
Add ToArray and ToList examples
banchan86 Aug 23, 2025
5e840eb
Add ToDictionary and ToLookup examples
banchan86 Aug 24, 2025
71bc18d
Add Subject examples
banchan86 Aug 25, 2025
a59bb6b
Add Buffer and Window operators examples
banchan86 Aug 26, 2025
f6fed55
Add dynamic Buffer and Window operator examples
banchan86 Aug 26, 2025
4484324
Add Amb and Switch operator examples
banchan86 Aug 26, 2025
8ee79a2
Add exception handling operator examples
banchan86 Aug 27, 2025
47af9d2
Add dynamic exception operator examples
banchan86 Aug 27, 2025
97a22c5
Add element insertion operators examples
banchan86 Aug 28, 2025
2a8b807
Add ElementIndex example
banchan86 Aug 28, 2025
59166ee
Add key selector operator examples
banchan86 Aug 28, 2025
8422736
Add key sorting operator examples
banchan86 Aug 28, 2025
0615e0c
Add Range and IgnoreElements examples
banchan86 Aug 29, 2025
27c635d
Fix misplaced workflows and svg images
banchan86 Aug 29, 2025
57483f0
Add Scan, SelectMany & CreateObservable examples
banchan86 Aug 29, 2025
79fabb5
Add TakeWhile and SkipWhile examples
banchan86 Sep 2, 2025
62ab272
Add Sink and Visualizer Examples
banchan86 Sep 2, 2025
4d1dcd1
Simplify some examples and reposition VisualizerWindow
banchan86 Sep 3, 2025
88d6816
Simplify more examples
banchan86 Sep 4, 2025
9b172fe
Reposition VisualizerWindow node for some examples
banchan86 Sep 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_Append.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.Append
---

[!include[Append](../articles/reactive-append.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_AsyncSubject.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.AsyncSubject
---

[!include[AsyncSubject](~/articles/subject-async.md)]
[!include[AsyncSubject](~/articles/subject-async.md)]

### Example

Use `AsyncSubject` to broadcast the last value to any subscriber.

:::workflow
![AsyncSubject Example](../workflows/reactive-asyncsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_AsyncSubject_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.AsyncSubject`1
---

[!include[AsyncSubject](~/articles/subject-async.md)]
[!include[AsyncSubject](~/articles/subject-async.md)]

### Example

Use `AsyncSubject` to broadcast the last value to any subscriber.

:::workflow
![AsyncSubject Example](../workflows/reactive-asyncsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_BehaviorSubject.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.BehaviorSubject
---

[!include[BehaviorSubject](~/articles/subject-behavior.md)]
[!include[BehaviorSubject](~/articles/subject-behavior.md)]

### Example

Use `BehaviorSubject` to broadcast the latest value to any subscriber.

:::workflow
![BehaviorSubject Example](../workflows/reactive-behaviorsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_BehaviorSubject_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.BehaviorSubject`1
---

[!include[BehaviorSubject](~/articles/subject-behavior.md)]
[!include[BehaviorSubject](~/articles/subject-behavior.md)]

### Example

Use `BehaviorSubject` to broadcast the latest value to any subscriber.

:::workflow
![BehaviorSubject Example](../workflows/reactive-behaviorsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
5 changes: 0 additions & 5 deletions apidoc/Bonsai_Reactive_CombineTimestamp.md

This file was deleted.

5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_CreateTimestamped.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.CreateTimestamped
---

[!include[CreateTimestamped](~/articles/reactive-createtimestamped.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_Prepend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.Prepend
---

[!include[Prepend](../articles/reactive-prepend.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_PublishSubject.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.PublishSubject
---

[!include[PublishSubject](~/articles/subject-publish.md)]
[!include[PublishSubject](~/articles/subject-publish.md)]

### Example

Use `PublishSubject` to broadcast values to any subscriber.

:::workflow
![PublishSubject Example](../workflows/reactive-publishsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_PublishSubject_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.PublishSubject`1
---

[!include[PublishSubject](~/articles/subject-publish.md)]
[!include[PublishSubject](~/articles/subject-publish.md)]

### Example

Use `PublishSubject` to broadcast values to any subscriber.

:::workflow
![PublishSubject Example](../workflows/reactive-publishsubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_ReplaySubject.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.ReplaySubject
---

[!include[ReplaySubject](~/articles/subject-replay.md)]
[!include[ReplaySubject](~/articles/subject-replay.md)]

### Example

Use `ReplaySubject` to broadcast all past and future values to any subscriber.

:::workflow
![ReplaySubject Example](../workflows/reactive-replaysubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
12 changes: 11 additions & 1 deletion apidoc/Bonsai_Reactive_ReplaySubject_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
uid: Bonsai.Reactive.ReplaySubject`1
---

[!include[ReplaySubject](~/articles/subject-replay.md)]
[!include[ReplaySubject](~/articles/subject-replay.md)]

### Example

Use `ReplaySubject` to broadcast all past and future values to any subscriber.

:::workflow
![ReplaySubject Example](../workflows/reactive-replaysubject-example.bonsai)
:::

[!include[SubjectAlternatives](../articles/reactive-subjectalternatives.md)]
6 changes: 5 additions & 1 deletion apidoc/Bonsai_Reactive_ResourceSubject.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
uid: Bonsai.Reactive.ResourceSubject
---

[!include[ResourceSubject](~/articles/subject-resource.md)]
[!include[ResourceSubject](~/articles/subject-resource.md)]

### Alternative

`ResourceSubject` is primarily used in niche applications involving device objects. For more typical scenarios, use [`AsyncSubject`](xref:Bonsai.Reactive.AsyncSubject) instead to broadcast the last value to subscribers.
6 changes: 5 additions & 1 deletion apidoc/Bonsai_Reactive_ResourceSubject_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
uid: Bonsai.Reactive.ResourceSubject`1
---

[!include[ResourceSubject](~/articles/subject-resource.md)]
[!include[ResourceSubject](~/articles/subject-resource.md)]

### Alternative

`ResourceSubject` is primarily used in niche applications involving device objects. For more typical scenarios, use [`AsyncSubject`](xref:Bonsai.Reactive.AsyncSubject) instead to broadcast the last value to subscribers.
12 changes: 12 additions & 0 deletions articles/reactive-accumulate.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@ title: Accumulate
![Marble diagram](~/images/reactive-accumulate.svg)

The `Accumulate` operator returns the current value of the cumulative sum each time the source sequence emits a notification. The result sequence terminates successfully when the source sequence terminates successfully.

### Example

Use `Accumulate` to continuously update a value by adding up the changes over time.

:::workflow
![Accumulate Example](../workflows/reactive-accumulate-example.bonsai)
:::

### Alternative

Use [`Sum`](xref:Bonsai.Reactive.Sum) instead to yield a single accumulated value at the end of a sequence.
12 changes: 12 additions & 0 deletions articles/reactive-amb.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@ title: Amb
![Marble diagram](~/images/reactive-amb.svg)

The `Amb` operator sets up a winner-take-all race condition between all source sequences. The first sequence to emit a notification will gain full control of the output, and all the other sequences will have their subscriptions immediatelly cancelled. `Amb` is most commonly used to ensure only one of many outcomes being evaluated in parallel is propagated.

### Example

Use `Amb` to propagate the first observable sequence that emits notifications.

:::workflow
![Amb Example](../workflows/reactive-amb-example.bonsai)
:::

### Alternative

Use [`Switch`](xref:Bonsai.Reactive.Switch) instead to propagate the latest observable sequence that emits notifications from a sequence of observable sequences.
16 changes: 16 additions & 0 deletions articles/reactive-append.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
uid: reactive-append
title: Append
---

### Example

Use `Append` to add an element to the end of a sequence.

:::workflow
![Append Example](../workflows/reactive-append-example.bonsai)
:::

### Alternative

Use [`Prepend`](xref:Bonsai.Reactive.Prepend) instead to add an element to the beginning of a sequence.
22 changes: 22 additions & 0 deletions articles/reactive-average.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,25 @@ title: Average
![Marble diagram](~/images/reactive-average.svg)

The `Average` operator collects all the values from the source sequence and emits a single floating-point number representing their arithmetic mean. The single result value is emitted only when the source sequence terminates successfully.

### Examples

Use `Average` to report the mean value at the end of the sequence.

:::workflow
![Average Example](../workflows/reactive-average-example.bonsai)
:::

#### Signal Smoothing

Use `Average` to smooth a noisy signal by grouping elements with [`WindowCount`](xref:Bonsai.Reactive.WindowCount), then applying `Average` inside a [`SelectMany`](xref:Bonsai.Reactive.SelectMany).

:::workflow
![Average Application Downsample](../workflows/reactive-average-application-downsample.bonsai)
:::

> [!NOTE]
> This operation is equivalent to [downsampling](https://en.wikipedia.org/wiki/Downsampling_(signal_processing)) and reduces the number of elements in the sequence. To implement a [moving average](https://en.wikipedia.org/wiki/Moving_average) that preserves the number of elements, you can adjust the `Skip` property in [`WindowCount`](xref:Bonsai.Reactive.WindowCount) to create sliding windows.

> [!NOTE]
> This example requires the `Bonsai.Design.Visualizers` package to be installed.
14 changes: 14 additions & 0 deletions articles/reactive-buffercount.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,17 @@ title: Buffer
`BufferCount` groups the notifications of the source sequence into chunks containing the number of elements specified in the <xref href="Bonsai.Reactive.BufferCount.Count"/> property. The overlap between the elements in each chunk can be controlled using the <xref href="Bonsai.Reactive.BufferCount.Skip"/> property.

If no skip value is provided, the chunks will be strictly non-overlapping, with a new chunk beginning when the previous chunk ends. If the skip value is less than the specified number of elements, chunks will be overlapping, with a new buffer created every `Skip` notifications. Finally, if the skip value is greater than the specified number of elements, there will be a gap between each chunk where elements from the source sequence will be dropped.

### Example

Use `BufferCount` to group elements into zero or more buffers based on element count.

:::workflow
![BufferCount Example](../workflows/reactive-buffercount-example.bonsai)
:::

### Alternatives

Use [`BufferTime`](xref:Bonsai.Reactive.BufferTime) instead to group elements into zero or more buffers based on timing information.

Use [`WindowCount`](xref:Bonsai.Reactive.WindowCount) instead to create new observable sequences based on element count.
14 changes: 14 additions & 0 deletions articles/reactive-buffertime.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,17 @@ title: BufferTime
The `BufferTime` operator groups the notifications of the source sequence into chunks, where each chunk contains the elements emitted during the specified <xref href="Bonsai.Reactive.BufferTime.TimeSpan"/>. The overlap between the elements in each chunk can be controlled using the <xref href="Bonsai.Reactive.BufferTime.TimeShift"/> property.

If no `TimeShift` is provided, the chunks will be strictly non-overlapping, with a new chunk beginning when the previous chunk ends. If `TimeShift` is smaller than `TimeSpan`, chunks will be overlapping, with a new buffer created every `TimeShift` interval. Finally, if `TimeShift` is larger than `TimeSpan`, there will be a time gap between each chunk where elements from the source sequence may be dropped.

### Example

Use `BufferTime` to group elements into zero or more buffers based on timing information.

:::workflow
![BufferTime Example](../workflows/reactive-buffertime-example.bonsai)
:::

### Alternatives

Use [`BufferCount`](xref:Bonsai.Reactive.BufferCount) instead to group elements into zero or more buffers based on element count.

Use [`WindowTime`](xref:Bonsai.Reactive.WindowTime) instead to create new observable sequences based on timing information.
12 changes: 12 additions & 0 deletions articles/reactive-buffertrigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ title: BufferTrigger
If neither buffer count nor buffer time span are specified, chunks will be strictly non-overlapping, with the previous chunk being closed when a new chunk is created. In this case, and only this case, the first chunk is also created immediately at the start of the sequence.

If the `Count` property or the `TimeSpan` property is specified, then a new chunk is created when the second sequence emits a notification, and it is automatically closed after either the specified number of elements is collected or the specified time span elapses. If a new chunk is created before the previous chunk is closed, then chunks will overlap, and any elements emitted during this period will be included in both buffers. If at any moment there is no open buffer, elements emitted from the source sequence will be dropped.

### Example

Use `BufferTrigger` to group elements into zero or more buffers based on notifications from a second sequence.

:::workflow
![BufferTrigger Example](../workflows/reactive-buffertrigger-example.bonsai)
:::

### Alternative

Use [`WindowTrigger`](xref:Bonsai.Reactive.WindowTrigger) instead to group elements into zero or more observable sequences based on notifications from a second sequence.
16 changes: 15 additions & 1 deletion articles/reactive-catch.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@ title: Catch

The `Catch` operator allows you to handle error notifications from a sequence by combining the output of multiple fallback sequences of the same type into a single sequence. `Catch` subscribes to the next sequence when the previous sequence produces an error, and emits all the values from that sequence until successful termination. If that sequence also terminates exceptionally, `Catch` then subscribes to the next sequence, and so forth. Each sequence is guaranteed to only start after the previous one terminates.

The resulting sequence will terminate successfully when any of the source sequences has terminated successfully, or exceptionally when all sequences have terminated with an error.
The resulting sequence will terminate successfully when any of the source sequences has terminated successfully, or exceptionally when all sequences have terminated with an error.

### Example

Use `Catch` to continue an observable sequence that terminated with an exception with the next observable sequence.

:::workflow
![Catch Example](../workflows/reactive-catch-example.bonsai)
:::

### Alternative

Use [`Retry`](xref:Bonsai.Reactive.Retry) instead to repeat subscription to the observable sequence if it terminates with an exception.

Use [`OnErrorResumeNext`](xref:Bonsai.Reactive.OnErrorResumeNext) instead to avoid raising an exception when all sequences have terminated with an error.
31 changes: 28 additions & 3 deletions articles/reactive-combinelatest.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,38 @@ title: CombineLatest

`CombineLatest` combines the values from each sequence which are closest in time. Whenever any of the source sequences emits a value (as long as all source sequences have emitted at least one value), `CombineLatest` takes the most recently emitted values from all other sequences and creates the combined result. `CombineLatest` will continue to emit values as long as at least one source sequence remains active (i.e. without terminating).

`CombineLatest` can be useful to temporally correlate separate sources (e.g. frames from different cameras, or the closest frame to a key press). It can also be useful when combining a sequence containing a single reference value with a possibly infinite sequence of values to be associated with the reference (e.g. subtracting a background from every frame).
### Examples

Use `CombineLatest` to combine multiple sources in time.

:::workflow
![CombineLatest Example](../workflows/reactive-combinelatest-example.bonsai)
:::

> [!Warning]
> Because `CombineLatest` emits a combined value whenever *any* of the source sequences emits a new value, the number of values emitted by `CombineLatest` is approximately the sum of the number of values in each sequence. If you need to discard redundant values you can filter the output, e.g. using [`Sample`](xref:Bonsai.Reactive.Sample) to use one of the source sequences as a master driver.
> As `CombineLatest` emits a combined value whenever *any* of the source sequences emits a new value, the number of values emitted by `CombineLatest` is approximately the sum of the number of values in each sequence. If you want to use only one of the source sequences as a master driver and discard redundant values, consider using [`Sample`](xref:Bonsai.Reactive.Sample).

:::workflow
![CombineLatest Example with Sample](../workflows/reactive-combinelatest-example-sample.bonsai)
:::

#### Video Synchronization

Use `CombineLatest` to combine multiple sources (e.g. frames from different cameras).

:::workflow
![CombineLatest Application Synchronize Video](../workflows/reactive-combinelatest-application-synchronizevideo.bonsai)
:::

> [!NOTE]
> This example requires the `Bonsai.Dsp`, `Bonsai.Vision` and `Bonsai.Vision.Design` packages to be installed.

### Alternative

Use [`WithLatestFrom`](xref:Bonsai.Reactive.WithLatestFrom) if you only need to combine two sources and want to discard redundant values.

### Higher-order operator

`CombineLatest` also works as a higher-order operator, so it can take as input a sequence of observable sequences. In this case, it will subscribe to each of the source sequences and start collecting all the latest values from each sequence. As soon as the outer sequence terminates, it will start reactively combining the latest values whenever any sequence changes, just as in the case of using `CombineLatest` with a fixed number of inputs.

![Higher order](~/images/reactive-combinelatestwindow.svg)
![Higher order](~/images/reactive-combinelatestwindow.svg)
Loading