1 Events
Data structures and functions for sequences of behavioral events
1.1 Event Structures
Behavioral events are discrete extensions of action through time, so that they have a discrete start time, duration, and endtime (although near-instantaneous events may have a duration indistinguiable from zero). Examples of event are a single lick, a discrete meal, a bodily movement such as a scratch, a burst of vocalization, or the lack of movement such as a rest period.
Events may also have a magnitude, depending on the type of behavior: a bout of licking consists of a certain magnitude (number) of licks, a meal may consist of a certain magnitude (grams) of food, a limb extension has a magnitude of distance traveled, or a magntiude of force exerted.
Furthermore, events are frequently hierarchical or decomposable, with the property that they are composed of subevents: a single liquid meal may be composed of 10 bouts of licking, with each bout containing between 100 to 1000 indiviudal licks, for example. Frequently the analysis of behavior requires reducing smaller units of events into larger units, eg. licks into meals.
Events are arranged in sequences across time, either as repetitions of the same event, or a sequence of varied event types interdigited and even co-extensive in time.
In BoutTime, event data (individual Event Datums) are collected into Vectors of Events, and packaged with metadata as Event Records.
There are multiple ways to represent and transform these time sequences, and to analyze and visualize them. See sections on Bout Analysis, Event Transitions, and Ethograms.
1.2 Event Datum
An event datum is an event that begins at a specific timestamp, posseses a magnitude, and persists for a duration. Every event specification requires a timestamp, but duration and magnitude are optional (and set to defaults of 0 and 1 respectively). The event is stored as a 5-vector. #(timestamp magnitude duration busy-time subeventsIndex subeventsCount)
An event can be 1 of 3 types (all represented by the same vector structure):
- An instantaneous (or very quick) event that occurs at a timestamp, but has no measurable (or recorded) duration. Each occurrence of the event has a fixed scalar magnitude of 1. An example might be a single lick recorded at timestamp 1138 ms. For convenience and efficiency, an instaneous event is stored as a single numeric timestamp eg 1138 as a durationless vector with magnitude 1, #(1138 1 0 0 0 0).
- An instantaneous event that occurs at a timestamp, and has no duration, but with a variable magnitude. This type of event could be stored as #(1138 3.14 0 0 0 0).
- A extended event, which has occurs (starts) at a timestamp, endures for a certain length of time (ie it has a duration), and has a variable scalar magnitude. An extended event is stored as a 3-vector #( timestamp magnitude duration). An example might be a foodjar-feeding bout recorded by an electronic balance as 3.14 g intake beginning at timestamp 43200 s across a duration of 300 s, stored as #(43200 3.14 300 0 0 0).
An event datum is an event that begins at a specific timestamp, posseses a magnitude, and persists for a duration. Every event specification requires a timestamp, but duration and magnitude are optional (and set to defaults of 0 and 1 respectively). The event is stored as a 5-vector.
Individual events are represented by a short vector:
'#(<timestamp> <magnitude> <duration> <busy-time> <subevents-count> <subevents-index>) |
Events typically are of 1 of 3 types:
- An instantaneous (or very quick) event that occurs at a timestamp, but has no measurable (or recorded) duration. Each occurrence of the event has a fixed scalar magnitude of 1. An example might be a single lick recorded at timestamp 1138 ms. For convenience and efficiency, an instaneous event is stored as a single numeric timestamp eg 1138 as a durationless vector with magnitude 1, #(1138 1 0 0 0 0).
- An instantaneous event that occurs at a timestamp, and has no duration, but with a variable magnitude. This type of event could be stored as #(1138 3.14 0 0 0 0).
- A extended event, which has occurs (starts) at a timestamp, endures for a certain length of time (ie it has a duration), and has a variable scalar magnitude. An extended event is stored as a 3-vector #( timestamp magnitude duration). An example might be a foodjar-feeding bout recorded by an electronic balance as 3.14 g intake beginning at timestamp 43200 s across a duration of 300 s, stored as #(43200 3.14 300 0 0 0).
timestamp
The time of onset of the event, relative to the start of the datafile. The timestamps ar relative to the start of the datafile, so they need to be added to the start-time of data collection to determine their wall-clock time.
The units of the timestamps can be set elsewhere, but the default assumption is that timestamps are in millseconds.
magnitude
The "size" of the event as measured with a relative factor. This may be determined by the data measurement (eg speed during a bout of running), or it may be as simple as the count of the underlying events (number of individual licks making up a bout of licking). For convenience, the magnitude of isolated "instanenous" events like a single lick are set to a magnitude of 1. When subevents are combined into a larger event, the magntiude of the combined event can be specified as the count of the subevents, the sum of the individual subevent magnitudes, or the sum of the indiviudal subevent durations.
duration
The duration is the time from the start of the event (the event’s timestamp) to the end of the event, from which the end-time of the event can de derived. "Instaneous" events can have zero duration. A sequence of simple repetitive events may all have the same duration, but the duration of each event in a sequence might also be diffferent.
busy-time
The "busy-time" of event, also known as the on-cycle, is the time within the event’s duration when the animal is actively engaged in the behavior. For example, an animal might eat a meal over a duration of 10 minutes from the first bite to the last bite, but pause for 15 seconds every minute of the meal. Then, even though the duration of the meal is 10 minutes, the "busy-time" is 7.5 minutes.
Of course, simple continuous events would have a busy-time equal to their duration.
subevents-count and subevents-index
When an event is composed of subevents from a higher-resolution subsequence, the event retains a reference to the composing subevents encoded as the index of the first subevent in the subsequence that contributes to this event, and the number of subsequent subevents (including the index subevents). This allows sequences to be easily decomposed into their subsequences,
pre-event interval
Events are constructed by
"(make-event #:timestamp #:magnitude #:duration #:busy #:subevents-index #:subevents-count #:preinterval )",
or when a sequence of timestamped events is loaded from a datafile by ...
The values of an individual event can be accessed using getters (eg "(event-timestamp theEvent), (event-duration theEvent)", etc., and set with setters "(event-timestamp-set! theEvent 86400)". See XXXX for the list of setters and getters.
1.3 Vectors of Events
(require "../event-series.rkt") | package: base |
struct
(struct eventkey (name symbol value description))
name : string? symbol : symbol? value : integer? description : string?
value
kEventKeys : (listof eventkey?)
"kTimestampKey"
"kMagnitudeKey"
"kDurationKey"
"kBusyKey"
"kSubEventsKey"
"kSubEventsCountKey"
"kPreIntervalKey"
procedure
(make-event #:timestamp ts [ #:magnitude mag #:duration dur #:busy busy #:subevents-index se #:subevents-count sec #:preinterval preint]) → vector? ts : nonnegative-integer? mag : number? = 1 dur : nonnegative-integer? = 0 busy : nonnegative-integer? = dur se : (or/c #f nonnegative-integer?) = kNotFoundKey sec : nonnegative-integer? = 0 preint : (or/c boolean? rational?) = #f
procedure
(make-zero-event) → vector?
procedure
(make-events-from-timestamps #:timestamps timestamps [ #:duration duration #:starttime starttime]) → vector? timestamps : (vectorof nonnegative-integer?) duration : nonnegative-integer? = 0 starttime : (or/c #f nonnegative-integer?) = #f
procedure
(set-event-preintervals #:events events [ #:starttime starttime]) → (vectorof vector?) events : (vectorof vector?) starttime : (or/c #f nonnegative-integer?) = #f
procedure
(event-val event index) → (or/c boolean? number?)
event : vector? index : integer?
procedure
(event-start event) → nonnegative-integer?
event : vector?
procedure
(event-end event) → nonnegative-integer?
event : vector?
procedure
(event-middle event) → nonnegative-integer?
event : vector?
procedure
(event-magnitude event) → number?
event : vector?
procedure
(event-duration event) → nonnegative-integer?
event : vector?
procedure
(event-busy event) → nonnegative-integer?
event : vector?
procedure
(event-subevents-index event) → (or/c #f nonnegative-integer?)
event : vector?
procedure
(event-subevents-count event) → nonnegative-integer?
event : vector?
procedure
(event-preinterval event) → (or/c #f nonnegative-integer?)
event : vector?
procedure
(event-set! event index val) → any
event : vector? index : integer? val : number?
procedure
(event-set-timestamp! event val) → any
event : vector? val : nonnegative-integer?
procedure
(event-set-magnitude! event val) → any
event : vector? val : number?
procedure
(event-set-duration! event val) → any
event : vector? val : nonnegative-integer?
procedure
(event-set-busy! event val) → any
event : vector? val : nonnegative-integer?
procedure
(event-set-subevents-index! event val) → any
event : vector? val : (or/c #f nonnegative-integer?)
procedure
(event-set-subevents-count! event val) → any
event : vector? val : nonnegative-integer?
procedure
(events->timestamps-list events) → list?
events : vector?
procedure
(sum-values #:value-key key #:event1 e1 #:event2 e2) → number? key : integer? e1 : vector? e2 : vector?
procedure
(interval-start-to-start #:event1 e1 #:event2 e2) → nonnegative-integer? e1 : vector? e2 : vector?
procedure
(interval-start-to-end #:event1 e1 #:event2 e2) → nonnegative-integer? e1 : vector? e2 : vector?
procedure
(interval-end-to-start #:event1 e1 #:event2 e2) → nonnegative-integer? e1 : vector? e2 : vector?
procedure
(interval-end-to-end #:event1 e1 #:event2 e2) → nonnegative-integer? e1 : vector? e2 : vector?
procedure
(events-ref events index) → vector?
events : vector? index : nonnegative-integer?
procedure
(events-count events) → nonnegative-integer?
events : vector?
procedure
(events-first events) → vector?
events : vector?
procedure
(events-last events) → vector?
events : vector?
procedure
(events-proper-vector events #:key key) → vector?
events : vector? key : integer?
procedure
(nth-event #:events events #:n n) → vector?
events : vector? n : nonnegative-integer?
procedure
(last-nth-event #:events events #:n n) → vector?
events : vector? n : nonnegative-integer?
procedure
(n-events #:events events #:n n) → vector?
events : vector? n : nonnegative-integer?
procedure
(last-n-events #:events events #:n n) → vector?
events : vector? n : nonnegative-integer?
procedure
(events-within-events sub-events super-events) → (vectorof vector?) sub-events : (vectorof vector?) super-events : (vectorof vector?)
sub-events: ---xxxx----xxxx---xxxxx----xx---xx----x----xxx-xxxx-x-xxx-xx--xxxx---xxx- super-events: -----ssssssssssssssssssss----------------sssssssssssssssssssssss--------- filtered: -----------xxxx---xxxxx--------------------xxx-xxxx-x-xxx-xx-------------
procedure
(scale-duration dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(scale-interevent dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(scale-busy dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(unscale-duration dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(unscale-interevent dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(unscale-busy dur) → (or/c #f nonnegative-integer?)
dur : (or/c #f nonnegative-integer?)
procedure
(find-and-scale-interval last-timestamp current-timestamp) → (or/c boolean? rational?) last-timestamp : (or/c #f nonnegative-integer?) current-timestamp : (or/c #f nonnegative-integer?)
1.4 Event Records
(require "../event-record.rkt") | package: base |
procedure
(make-event-record #:name name #:events events #:color color [ #:file-start-time file-start-time #:subrecord subrecord #:type type]) → hash? name : string? events : vector? color : string? file-start-time : integer? = 0 subrecord : vector? = null type : string? = "recorder"
a hash with
’events: vector of events ’name: name of events ’color: color to use when plotting this event series ’subrecord: the event-record containing the subevents, if events are devired from the sequence of subevents ’min-size [min-size 0] ’min-ibi ’binsize
’file-start-time taken from the data file
extended event record includes a bunch of derived
’bouts – events vector using find-bouts
derived, using kMagnitudeKey as the event quantity
’binned – events vector using binned-event-vals ’cumul – events vector using cumulative-events ’sum – sum-of-events ’mean – mean-of-events ’max – max-of-events ’min – min-of-events ’max-density – max-density-of-events
procedure
(make-extended-event-record #:name name #:events events #:color color #:min-ibi ibi [ #:file-start-time file-start-time #:subrecord subrecord #:type type #:min-size min-size #:binsize binsize]) → hash? name : string? events : vector? color : string? ibi : nonnegative-integer? file-start-time : (or/c #f nonnegative-integer?) = #f subrecord : vector? = null type : string? = "recorder" min-size : number? = 0 binsize : nonnegative-integer? = 300000
procedure
(read-event-record-from-data file-rows #:eventname type #:expt expt) → hash? file-rows : list? type : string? expt : list?
procedure
(read-all-event-records-from-data file-rows #:expt expt) → (listof hash?) file-rows : list? expt : list?
procedure
(read-event-record-from-file data-file-path #:eventname type #:expt expt) → hash? data-file-path : string? type : string? expt : list?
procedure
(file->event-record #:filename filename #:name name #:color color #:min-ibi ibi #:binsize binsize) → hash? filename : string? name : string? color : string? ibi : nonnegative-integer? binsize : nonnegative-integer?