Collection Producers
The collection producer operators maintain collections of events over the data lifecycle.
Unary collection producers
The unary collection producers maintain a collection based on static parameters.
window
The window
operator collects Events over a duration and re-emits them as a Collection as they enter and leave a fixed-width window of time.
By default the window is set to the authoritative domain's temporal width.
- A
<RealTimeDomain window={30_000} />
will cause thewindow
operator to have a window length of 30 seconds. - A
<StaticDomain />
will cause thewindow
operator to have an infinite window length.
The window length can be changed with the windowLength
argument. The windowLength
is exclusive of the oldest point. A 30 second window does not include events exactly 30 seconds away from 'now'.
The example below produces a rolling 2 second average of the data source.
import { useDataTransformer } from '@electricui/timeseries-react'import { DataTransformer , window , mean } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const rollingAverage = mean (window (dataSource , 2_000)) return rollingAverage })
buffer
The buffer
operator collects up to N Event
s and emits a Collection each time a new Event
comes in.
If more than N events are added, old ones are evicted.
The optional third argument, onlyEmitAtCapacity
specifies if the operator should wait until the capacity is reached before emitting the first collection.
The example below waits until 64 items have been buffered, before maintaining the latest 64 items as a Collection.
import { useDataTransformer } from '@electricui/timeseries-react'import { buffer } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const buffered = buffer (dataSource , 64, true) return buffered })
batch
The batch
operator collects events and re-emits a fixed size Collection of them once the capacity
is reached.
Prefer the buffer
or window
operators unless you need non-overlapping slices of input data with relatively high latency.
The example below collects 512 events, then emits them all at once.
import { useDataTransformer } from '@electricui/timeseries-react'import { batch } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const batchOf512 = batch (dataSource , 512) return batchOf512 })
head
The head
operator collects events and maintains a Collection of the top-N items as defined by an arbitrary order.
By default the ordering is by time, and the top 1 item is maintained, producing the 'earliest' event.
The operator can consume a regular Queryable or another Collection Queryable. If a non-Collection queryable is passed, it is implicitly wrapped with a window
operator.
The example below maintains a Collection of the top 10 events by 'voltage' in the past 30 seconds.
import { useDataTransformer } from '@electricui/timeseries-react'import { head , window } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const thirtySecondWindow = window (dataSource , 30_000) const top10ByVoltage = head (thirtySecondWindow , { N : 10, orderBy : (data , time , tags ) => data .voltage }) return top10ByVoltage })
tail
The tail
operator collects events and maintains a Collection of the bottom-N items as defined by an arbitrary order.
By default the ordering is by time, and the bottom 1 item is maintained, producing the 'latest' event.
The operator can consume a regular Queryable or another Collection Queryable. If a non-Collection queryable is passed, it is implicitly wrapped with a window
operator.
The example below maintains a Collection of the 'rightmost' 10 events by their x coordinate in the past 30 seconds.
import { useDataTransformer } from '@electricui/timeseries-react'import { tail , window } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const thirtySecondWindow = window (dataSource , 30_000) const rightMost10 = tail (thirtySecondWindow , { N : 10, orderBy : (data , time , tags ) => data .x }) return rightMost10 })
Binary collection producers
The binary collection producers utilise an external source of data to drive the 'selection' of events. If a non-collection queryable is passed as the input, the operator implicitly wraps it with a window
operator, selecting the authoritative domain's window length of data.
Each operator comes in a singular and plural variant. The valueAccessor
and searchRegionAccessor
names are specialised to the type of data the operator indexes on. They each follow closely to the following signature format, with minor variations based on the data type.
The singular variant maintains a selection based on a singular input search source.
- It can discard inputs by passing a
null
to thevalueAccessor
. Otherwise, this is the data used to index the event. - It can discard searches by passing a
null
to thesearchRegionAccessor
. Otherwise, this defines the search region. - It can discard matches based on the result of the
predicate
function. - It can remap the resulting event data and tags with the
mapResult
andtagResult
functions. - Only the differences between the SearchRegions are emitted. If a search region is 'extended' for example, only the 'new' events will be emitted.
declare type CollectValueSingularStructure = ( queryable, searchSource, { valueAccessor?: (data, time, tags) => Value | null, searchRegionAccessor?: (data, time, tags) => SearchRegion, predicate?: (data, time, tags, value, searchData, searchTags, searchRegion) => boolean, mapResult?: (data, time, tags, value, searchData, searchTags, searchRegion) => Result, tagResult?: (data, time, tags, value, searchData, searchTags, searchRegion) => ResultTags, })
The plural variant maintains multiple selections based on a Collection of input search source. It has similar features to the singular variant:
- It can discard inputs by passing a
null
to thevalueAccessor
. Otherwise, this is the data used to index the event. - It can discard searches by passing a
null
to thesearchRegionAccessor
. Otherwise, this defines the search region. - It can discard matches based on the result of the
predicate
function. - It can remap the resulting event data and tags with the
mapResult
andtagResult
functions.
The notable differences are that:
- The final Collection is only maintained at the granularity of the SearchRegion. If a SearchRegion is 'extended' for example, all the events in the old region are removed, then the events in the new region are added back. For this reason, if only one search region is maintained, prefer the singular variant of the operator.
- The resulting event data can also be remapped in time, using the
retimeResult
function.
declare type CollectValuesPluralStructure = collectValues( queryable, searchSource, { valueAccessor?: (data, time, tags) => Value, searchRegionAccessor?: (data, time, tags) => SearchRegion, predicate?: (data, time, tags, value, searchData, searchTags, searchRegion) => boolean, mapResult?: (data, time, tags, value, searchData, searchTags, searchRegion) => Result, tagResult?: (data, time, tags, value, searchData, searchTags, searchRegion) => ResultTags, retimeResult?: (data, time, tags, value, searchData, searchTags, searchRegion) => Time, })
collectTimeSpan
The singular form collectTimeSpan
operator maintains a Collection of events within a TimeSpan
of { min: Time, max: Time }
.
There is no valueAccessor
, as it automatically selects the Event times.
The example below selects the region of time defined by the mouse drag minimum and maximum x coordinates. If the mouse hasn't completed, or has cancelled the drag, then it selects nothing.
import { useDataTransformer } from '@electricui/timeseries-react'import { useMouseSignal } from '@electricui/components-desktop-charts'import { collectTimeSpan } from '@electricui/dataflow' const [mouseSignal , captureRef ] = useMouseSignal () const dataTransformer = useDataTransformer (() => { const selected = collectTimeSpan (dataSource , mouseSignal , { // If the mouse has dragged, return the drag x min and max, // otherwise return null, selecting nothing searchRegionAccessor : (data , time , tags ) => { if (data .hasDragged ) { return ({ min : data .dragXMin , max : data .dragXMax }) } return null }, // just select the raw data (the default) mapResult : (data , time , tags , searchData , searchTags , searchRegion ) => data }) return selected })
collectTimeSpans
The plural form collectTimeSpans
operator maintains a Collection of events within a Collection of TimeSpan
s of { min: Time, max: Time }
.
There is no valueAccessor
, as it automatically selects the Event times.
The example below selects the 1 second surrounding each of the 'peak' events within the chart window. It tags the resulting events with the peak that caused its collection.
import { useDataTransformer } from '@electricui/timeseries-react'import { collectTimeSpans , window } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const chartPeaks = window (peakDS ) const selected = collectTimeSpans (dataSource , chartPeaks , { // Pass through the peak time via an additional parameter searchRegionAccessor : (data , time , tags ) => ({ min : time - 500, max : time + 500, peakTime : time }), // Tag each result with the time of the peak tagResult : (data , time , tags , searchData , searchTags , searchRegion ) => ({ peakTime : searchRegion .peakTime }) }) return selected })
collectBoundingBox
The singular form collectBoundingBox
operator maintains a Collection of events within a BoundingBox
of { xMin: number, yMin: number, xMax: number, yMax: number }
.
The positionAccessor
is used to define the position of an Event. The searchBoundingBoxAccessor
is used to define the search region.
The example below selects the region of time defined by the mouse drag coordinates. If the mouse hasn't completed, or has cancelled the drag, then it selects nothing.
import { useDataTransformer } from '@electricui/timeseries-react'import { useMouseSignal , MouseData } from '@electricui/components-desktop-charts'import { collectBoundingBox } from '@electricui/dataflow' const [mouseSignal , captureRef ] = useMouseSignal () const dataTransformer = useDataTransformer (() => { const selected = collectBoundingBox (dataSource , mouseSignal , { // Select the x and y position from the event. This is the default. positionAccessor : (data , time , tags ) => ({ x : data .x , y : data .y }), // If the mouse has dragged, return the drag bounding box, // otherwise return null, selecting nothing searchBoundingBoxAccessor : (data , time , tags ) => { if (data .hasDragged ) { return ({ xMin : data .dragXMin , xMax : data .dragXMax , yMin : data .dragYMin , yMax : data .dragYMax }) } return null }, // just select the raw data (the default) mapResult : (data , time , tags , searchData , searchTags , searchRegion ) => data , }) return selected })
collectBoundingBoxes
The plural form collectBoundingBoxes
operator maintains a Collection of events within a Collection of BoundingBox
s of { xMin: number, yMin: number, xMax: number, yMax: number }
.
The positionAccessor
is used to define the position of an Event. The searchBoundingBoxAccessor
is used to define the search region.
The example below selects all particle count events within 100 units of the 'impact sites', within the chart temporal range. It tags the resulting events with the impact site coordinates that caused its collection.
import { useDataTransformer } from '@electricui/timeseries-react'import { collectBoundingBoxes , window } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const impactSitesWithinTemporalRange = window (impactSites ) const selected = collectBoundingBoxes (dataSource , impactSitesWithinTemporalRange , { // Select the x and y position from the event. This is the default. positionAccessor : (data , time , tags ) => ({ x : data .x , y : data .y }), // Initially search for the bounding box surrounding 100 units on each side searchBoundingBoxAccessor : (data , time , tags ) => ({ xMin : data .x - 100, xMax : data .x + 100, yMin : data .y - 100, yMax : data .y + 100, impactX : data .x , impactY : data .y , }), // Use the predicate to filter to a 100 unit radius 'circle' instead of just the bounding box predicate : (data , time , tags , position , searchData , searchTags , searchRegion ) => { const distance = Math .sqrt ( Math .pow (position .x + searchRegion .impactX , 2) + Math .pow (position .y + searchRegion .impactY , 2) ) return distance <= 100 }, // Tag each result with the position of the impact site tagResult : (data , time , tags , position , searchData , searchTags , searchRegion ) => ({ impactX : searchRegion .impactX , impactY : searchRegion .impactY }), }) return selected })
collectValueSpan
The singular form collectValueSpan
operator maintains a Collection of events within a SearchRegion
of { min: V, max: V }
.
The valueAccessor
is used to define the value of an Event. The searchRegionAccessor
is used to define the search region. The order
operator is used to define the ordering of values if they are non-number.
The example below selects the region of voltage values defined by the mouse drag coordinates on the y coordinate. If the mouse hasn't completed, or has cancelled the drag, then it selects nothing.
import { useDataTransformer } from '@electricui/timeseries-react'import { useMouseSignal , MouseData } from '@electricui/components-desktop-charts'import { collectValueSpan } from '@electricui/dataflow' const [mouseSignal , captureRef ] = useMouseSignal () const dataTransformer = useDataTransformer (() => { const selected = collectValueSpan (dataSource , mouseSignal , { // Order by the voltage valueAccessor : (data , time , tags ) => data .voltage , // If the mouse has dragged, return the drag bounding defined by the y coordinate, // otherwise return null, selecting nothing searchRegionAccessor : (data , time , tags ) => { if (data .hasDragged ) { return ({ min : data .dragYMin , max : data .dragYMax }) } return null }, // just select the raw data (the default) mapResult : (data , time , tags , searchData , searchTags , searchRegion ) => data , }) return selected })
collectValueSpans
The plural form collectValueSpans
operator maintains a Collection of events within a Collection of SearchRegion
of { min: V, max: V }
.
The valueAccessor
is used to define the value of an Event. The searchRegionAccessor
is used to define the search region. The order
operator is used to define the ordering of values if they are non-number.
The example below selects all events within 100 units of the trigger voltage, within the chart temporal range. It tags the resulting events with the trigger voltage that caused its collection.
import { useDataTransformer } from '@electricui/timeseries-react'import { collectValueSpans , window } from '@electricui/dataflow' const dataTransformer = useDataTransformer (() => { const triggersWithinTemporalRange = window (triggers ) const selected = collectValueSpans (dataSource , triggersWithinTemporalRange , { // Select the x and y position from the event. This is the default. valueAccessor : (data , time , tags ) => data .voltage , // Search for values within 100 units of the trigger voltage searchRegionAccessor : (data , time , tags ) => ({ min : data - 100, max : data + 100, triggerVoltage : data , }), // Tag each result with the trigger voltage tagResult : (data , time , tags , position , searchData , searchTags , searchRegion ) => ({ triggerVoltage : searchRegion .triggerVoltage }), }) return selected })