Chronobiology¶
A python package to calculate and plot circadian cycles data.
Introduction¶

Circadian rhythms are ~24 hour cycles of physiology and behaviour that occur in virtually all organisms from bacteria to man. These rhythms are generated by an internal biological clock and persist even in isolation from any external environmental cues. In humans, circadian rhythms in activity are typically measured using calibrated wrist-worn accelerometers. By contrast, the activity of laboratory animals is typically measured using home cage running wheels. Circadian data are typically double plotted as actograms, showing activity across multiple days.
The circadian field has developed standard methods for analysing circadian rhythms. This primarily includes methods to detect recurring features in the data, enabling the period length of activity cycles to be determined. Under entrained conditions, this period will normally be determined by environmental zeitgebers A range of different methods are used to determine the underlying period in biological time series. Three of the most commonly used are the Enright periodogram, Fourier analysis and the Lomb-Scargle periodogram. In addition, activity onset is also frequently used to characterise phase shifts in rhythms in response to environmental zeitgebers.
Circadian disruption may occur as a result of environmental conditions. This includes misalignment (when two or more rhythms adopt an abnormal phase relationship) and desynchrony (when two or more rhythms exhibit a different period). A range of approaches have been used to assess circadian disruption. These methods range from simple visual inspection of actograms to metrics such as periodogram power, variability in activity onset, light phase activity, activity bouts, interdaily stability, intradaily variability and relative amplitude.
This package provides a set of tools to calculate and plot these parameters based on activity measurements for further inspection and analysis.
For more theory see the following paper:
Telling the Time with a Broken Clock: Quantifying Circadian Disruption in Animal Models
Storing data¶
Activity data collected during an experiment is usually represented by an array of records with the following data:
time of measurement;
measured activity value;
time of day marker (night or day).
We recommend InfluxDB to store activity data.
Only InfluxDB v1.x is supported, don’t use InfluxDB v2.x.
Each searies of measurements should be represented by a separate InfluxDB table with the following fields:
value
– numeric values obtained by sensors;is_night
– day/night marker (True
for nighttime measurements andFalse
for daytime measurements).
Other data (like sensor_id
in case of multiple sensors) can also be included in the table as tags.
In InfluxDB, data can be stored as a field or tag. Tags are more efficient to construct WHERE-queries but they can hold only string data. So it’s better to have value
and is_night
stored as fields and other data (required for filtering purpuses) stored as tags.
For installing and configuring InfluxDB see the official documentation. Once your InfluxDB is initialized and configured, you are ready to write data to it.
Writing data to InfluxDB using Python¶
In the following example, random measurements are generated and written to database via InfluxDBClient
which can be downloaded using pip:
$ pip install influxdb
[1]:
from influxdb import InfluxDBClient
import json
from datetime import datetime, timedelta
import random
[2]:
# Create a client to access the database.
client = InfluxDBClient('localhost', 8086, 'admin', 'pass', database='my_db')
[3]:
# Generate random measurements.
measurements=[]
for i in range(5):
measurements.append({
'measurement': 'test_series',
'tags': {
'sensor_id': '1',
},
'time': datetime.fromisoformat('2021-01-01') + timedelta(hours=i),
'fields': {
'value': random.uniform(1, 10),
'is_night': True,
}
})
measurements
[3]:
[{'measurement': 'test_series',
'tags': {'sensor_id': '1'},
'time': datetime.datetime(2021, 1, 1, 0, 0),
'fields': {'value': 2.636775703935856, 'is_night': True}},
{'measurement': 'test_series',
'tags': {'sensor_id': '1'},
'time': datetime.datetime(2021, 1, 1, 1, 0),
'fields': {'value': 9.634964674586048, 'is_night': True}},
{'measurement': 'test_series',
'tags': {'sensor_id': '1'},
'time': datetime.datetime(2021, 1, 1, 2, 0),
'fields': {'value': 5.488104584244404, 'is_night': True}},
{'measurement': 'test_series',
'tags': {'sensor_id': '1'},
'time': datetime.datetime(2021, 1, 1, 3, 0),
'fields': {'value': 2.3051122236289237, 'is_night': True}},
{'measurement': 'test_series',
'tags': {'sensor_id': '1'},
'time': datetime.datetime(2021, 1, 1, 4, 0),
'fields': {'value': 5.834270867285628, 'is_night': True}}]
[4]:
# Insert generated data to the database.
client.write_points(measurements);
[5]:
# Show the inserted data.
client.query('''SELECT (*) FROM "test_series"''')
[5]:
ResultSet({'('test_series', None)': [{'time': '2021-01-01T00:00:00Z', 'is_night': True, 'sensor_id': '1', 'value': 2.636775703935856}, {'time': '2021-01-01T01:00:00Z', 'is_night': True, 'sensor_id': '1', 'value': 9.634964674586048}, {'time': '2021-01-01T02:00:00Z', 'is_night': True, 'sensor_id': '1', 'value': 5.488104584244404}, {'time': '2021-01-01T03:00:00Z', 'is_night': True, 'sensor_id': '1', 'value': 2.3051122236289237}, {'time': '2021-01-01T04:00:00Z', 'is_night': True, 'sensor_id': '1', 'value': 5.834270867285628}]})
Selecting data¶
Once your data is written to InfluxDB, you are ready to select it for analysis.
This package provides the DBQuery class to connect to your InfluxDB and read data from it. Here is an example of it’s usage.
[1]:
from chronobiology.chronobiology import DBQuery
[2]:
# Create a client to access a local database.
client = DBQuery('my_db', 'admin', 'pass')
Getting measurements¶
[3]:
# Get all measurements found in database.
client.get_measurements()
[3]:
['test_series']
Getting tags¶
[4]:
# Get tags of a series.
client.get_tags('test_series')
[4]:
['sensor_id']
[5]:
# Try to get tags of a nonexistent series.
client.get_tags('foo')
[5]:
[]
Getting fields¶
[6]:
# Get fields of a series.
client.get_fields('test_series')
[6]:
['is_night', 'value']
[7]:
# Get fields of a series with their types.
client.get_fields('test_series', return_types=True)
[7]:
(['is_night', 'value'], ['boolean', 'float'])
[8]:
# Try to get fields of a nonexistent series.
client.get_fields('foo')
[8]:
[]
Getting keys¶
Keys is a set of all possible values of a tag.
[9]:
# Get keys of a series tag.
client.get_keys('test_series', 'sensor_id')
[9]:
['1']
[10]:
# Try to get keys of a nonexistent series.
client.get_keys('foo', 'sensor_id')
[10]:
[]
[11]:
# Try to get keys of a nonexistent tag.
client.get_keys('test_series', 'foo')
[11]:
[]
Getting data¶
Data includes both fields and tags.
[12]:
# Get all data from a series.
client.get_data('test_series', '*')
[12]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'is_night': array([ True, True, True, True, True]),
'value': array([2.6367757 , 9.63496467, 5.48810458, 2.30511222, 5.83427087]),
'sensor_id': array(['1', '1', '1', '1', '1'], dtype='<U1')}
[13]:
# Get values of a single field of a series.
client.get_data('test_series', 'value')
[13]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'value': array([2.6367757 , 9.63496467, 5.48810458, 2.30511222, 5.83427087])}
[14]:
# Get values of multiple fields/tags of a series.
client.get_data('test_series', ['value', 'sensor_id'])
[14]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'value': array([2.6367757 , 9.63496467, 5.48810458, 2.30511222, 5.83427087]),
'sensor_id': array(['1', '1', '1', '1', '1'], dtype='<U1')}
[15]:
# Get data filtered by a single key value.
client.get_data('test_series', '*', keys={'sensor_id': '1'})
[15]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'is_night': array([ True, True, True, True, True]),
'value': array([2.6367757 , 9.63496467, 5.48810458, 2.30511222, 5.83427087]),
'sensor_id': array(['1', '1', '1', '1', '1'], dtype='<U1')}
[16]:
# Get data filtered by multiple key values.
client.get_data('test_series', '*', keys={'sensor_id': ['1', '2']})
[16]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'is_night': array([ True, True, True, True, True]),
'value': array([2.6367757 , 9.63496467, 5.48810458, 2.30511222, 5.83427087]),
'sensor_id': array(['1', '1', '1', '1', '1'], dtype='<U1')}
[17]:
# Get data newer than a given timestamp (inclusive).
client.get_data('test_series', '*', keys={'sensor_id': '1'}, start='2021-01-01 02:00:00')
[17]:
{'time': array(['2021-01-01T02:00:00.000000000', '2021-01-01T03:00:00.000000000',
'2021-01-01T04:00:00.000000000'], dtype='datetime64[ns]'),
'is_night': array([ True, True, True]),
'value': array([5.48810458, 2.30511222, 5.83427087]),
'sensor_id': array(['1', '1', '1'], dtype='<U1')}
[18]:
# Get data older than a given timestamp (exclusive).
client.get_data('test_series', '*', keys={'sensor_id': '1'}, stop='2021-01-01 03:00:00')
[18]:
{'time': array(['2021-01-01T00:00:00.000000000', '2021-01-01T01:00:00.000000000',
'2021-01-01T02:00:00.000000000'], dtype='datetime64[ns]'),
'is_night': array([ True, True, True]),
'value': array([2.6367757 , 9.63496467, 5.48810458]),
'sensor_id': array(['1', '1', '1'], dtype='<U1')}
Analyzing data¶
Class CycleAnalyzer is used for calculating and plotting circadian cycles data.
For more info about the analysis methods, see the paper.
Here’s an example of analyzing randomly generated activity data.
[1]:
import numpy as np
from chronobiology.chronobiology import CycleAnalyzer, generate_data
[2]:
# Generate random activity data.
data = generate_data()
# Prepare input arrays for CycleAnalyzer.
# When working with InfluxDB, same arrays must be selected using a DBQuery instance.
timestamps = data['time'] # timestamps of measurements
values = data['value'] # activity values
nights = data['is_night'] # night activity markers
print(f'{len(timestamps)} measurements generated.')
np.set_printoptions(threshold=10)
data
870 measurements generated.
[2]:
{'time': array(['2020-01-01T00:03:00.000000000', '2020-01-01T03:29:00.000000000',
'2020-01-01T03:53:00.000000000', ...,
'2020-01-10T20:42:00.000000000', '2020-01-10T22:02:00.000000000',
'2020-01-10T22:47:00.000000000'], dtype='datetime64[ns]'),
'value': array([1, 1, 1, ..., 1, 1, 1]),
'is_night': array([False, True, True, ..., True, True, True])}
[3]:
# Create a cycle analyzer.
ca = CycleAnalyzer(timestamps, values, nights)
Actogram¶
The most obvious way of assessing circadian disruption is to simply look at experimental actograms. This visual inspection should always take the form of circadian disruption into account, and whether this is environmental or genetic in origin. This will also determine the appropriate controls, be they baseline conditions or wildtype littermates, respectively. Furthermore, when studying circadian disruption under different lighting paradigms, comparing activity relative to the external LD cycle is critical. This initial visual inspection of actogram data will guide the choice of which additional measurements are likely to be most informative.
[4]:
ca.plot_actogram()

Periodogram¶
The power of a periodogram provides a measure of the strength and regularity of the underlying rhythm, with higher values indicating robust rhythms. In circadian disruption — where rhythms are typically less robust — periodogram power is expected to be reduced and low values may indicate the absence of a significant circadian rhythm. The power of the chi-square periodogram (\(Q_p\)) has been widely used as a measure of the robustness of circadian rhythms, and can be traced back to studies on the effects of constant light on the strength of activity and sleep rhythms in rats. Analysis of \(Q_p\) based upon simulated and empirical data sets has shown that this provides a valuable measure of the robustness of circadian rhythms. Periodogram analysis is particularly informative in internal desynchrony, where the power of multiple periodicities within a dataset will be evident.
[5]:
ca.plot_periodogram()

Activity oneset¶
A hallmark of normal circadian function is that activity onset is consistent from day to day. In most records, the onset of activity is typically a more precise phase marker than the offset of activity. As such, the variability in activity onset across multiple days – either relative to the light/dark cycle (phase angle of entrainment) or under constant conditions – provides a useful metric to describe the precision of circadian rhythms. Phase angle of entrainment and the variability in activity onset have been widely used in the study of circadian entrainment. Activity onset is particularly informative when studying circadian misalignment and chronodisruption, where the phasing of activity with regard to environmental zeitgebers is expected to differ.
[6]:
ca.activity_onset()
[6]:
array(['2020-01-01T03:29', '2020-01-02T02:45', '2020-01-03T02:37',
'2020-01-04T02:43', '2020-01-05T03:11', '2020-01-06T01:59',
'2020-01-07T03:43', '2020-01-08T02:20', '2020-01-09T01:50',
'2020-01-10T02:02'], dtype='datetime64[m]')
[7]:
ca.plot_activity_onset()

Light phase activity¶
In nocturnal species, such as laboratory mice, activity is normally confined to the dark phase of the light/dark cycle. A hallmark of disrupted rhythms is therefore an increased activity in the normally inactive light phase, and such changes are expected to occur in both circadian misalignment and chronodisruption. In diurnal species, dark phase activity can similarly be used to quantify the amount of activity occurring in the normal inactive phase. Light phase activity has been widely used to study defects in circadian entrainment to light as well as in disease-relevant models. Light phase activity also provides an ideal measure to assess the impact of misaligned feeding, a specific example of circadian misalignment.
[8]:
ca.light_activity(auc=True)
[8]:
(array([0.0952381 , 0.05813953, 0.03529412, 0.04545455, 0.08045977,
0.04705882, 0.05617978, 0.02272727, 0.03370787, 0.02247191]),
0.04942528735632184,
0.4978093187109366)
[9]:
ca.plot_light_activity()

Activity bouts¶
As a result of less consolidated activity and rest phases, circadian disruption is associated with an increased number and reduced duration of activity bouts. The number and duration of activity bouts are frequently used as a measure of fragmentation in circadian disruption. Due to the inappropriate phasing of activity/rest cycles with regard to the external environmental, circadian misalignment, internal desynchrony and chronodisruption are all expected to affect activity bouts.
[10]:
ca.daily_bouts()
[10]:
(array([57, 67, 62, 68, 64, 67, 63, 66, 68, 62]),
array([1.47368421, 1.28358209, 1.37096774, 1.29411765, 1.359375 ,
1.26865672, 1.41269841, 1.33333333, 1.30882353, 1.41935484]))
[11]:
ca.plot_daily_bouts()

[12]:
ca.plot_bout_histogram()

Inter-daily stability¶
Inter-daily stability (IS) measures the day-to-day reproducibility of rest/activity cycles. Patterns of activity are typically reproducible in healthy individuals, whereas circadian disruption results in more variable rhythms. IS was first described in the study of elderly human patients with Alzheimer’s disease. It has subsequently been widely used in a number of human studies, and has also been adopted for studying circadian disruption in animal models. Due to the day-to-day changes in the relationship between circadian and environmental time, decreased IS may be expected in internal desynchrony. However, circadian misalignment and chronodisruption may not influence IS if a stable new phase-relationship is established.
[13]:
ca.interdaily_stability()
[13]:
0.9509106984969055
Intra-daily variability¶
Intra-daily variability (IV) is a measure of the fragmentation of activity rhythms. First introduced for the study of patients with Alzheimer’s disease, like IS it has been readily adopted for the study of animal models of circadian disruption. IV measures the frequency of transitions between activity and rest across the day. More transitions between activity and rest result in higher IV scores. As with activity bouts, circadian misalignment, internal desynchrony and chronodisruption may all increase IV due to the inappropriate phasing of activity/rest cycles with regard to the external environment. A good example of this occurs in aging, where IV increases steadily with age in mice.
[14]:
ca.intradaily_variability()
[14]:
(array([0.67764081, 0.44996891, 0.46650498, 0.50534161, 0.53465811,
0.57466193, 0.62592347, 0.44469921, 0.53629512, 0.64607892]),
0.5521986259617444)
[15]:
ca.plot_intradaily_variability()

Relative amplitude¶
Perhaps the most obvious measure of the strength of any biological rhythm is its amplitude. A simple metric that has been widely used in human studies is relative amplitude (RA), again originating from studies in patients with Alzheimer’s disease. RA is a simple measure of the difference between periods of peak activity and rest. As healthy rhythms are assumed to display consolidated activity and rest periods, RA is expected to be reduced when normal circadian rhythms are disrupted. Both circadian misalignment and chronodisruption will reduce RA, with internal desynchrony potentially resulting in RA values that fluctuate as periods move in and out of phase.
[16]:
ca.relative_amplitude(auc=True)
[16]:
(array([0.89333333, 0.94871795, 0.94736842, 0.90123457, 0.85365854,
0.8974359 , 0.85365854, 0.90243902, 0.95121951, 0.85542169]),
0.8998748435544431,
8.998188196576098)
[17]:
ca.plot_relative_amplitude()

Chronobiology module¶
Main module providing classes and methods to collect, generate, calculate and plot circadian cycles data.
Classes
Class to access InfluxDB 1.x and select records from it. |
|
Class to calculate and plot circadian cycles data. |
Methods
Generate random input data. |
|
Generate a random |
- class chronobiology.chronobiology.DBQuery(database, username, password, host='localhost', port=8086)¶
Class to access InfluxDB 1.x and select records from it.
- Parameters
database (str) – Name of the database.
username (str) – Name of user.
password (str) – User password.
host (str, optional) – IP adress, defaults to
localhost
.port (int, optional) – Connection port, defaults to
8086
.
Methods
Get list of all measurments (series) in the database.
Get all tags (tag names) in a series.
Get all fields in a series.
Get list of all tag values for a given tag in a series.
Get data (records) for specified fields/tags in a series.
- get_measurements()¶
Get list of all measurments (series) in the database.
- Return type
list[str]
- Returns
List of all measurement names in the database.
- get_tags(series)¶
Get all tags (tag names) in a series.
- Parameters
series (str) – Name of the series.
- Return type
list[str]
- Returns
List of all tag names in the series.
Note
Returns an empty list if the query does not return any vaues, for example, if there are no tags in the series or if there is no series with the given name.
- get_fields(series, return_types=False)¶
Get all fields in a series.
- Parameters
series (str) – Name of the series.
return_types (bool, optional) – Indicates if field types should be returned, defaults to
False
.
- Return type
list[str]|(list[str], list[str])
- Returns
- If
return_type == False
List of field names.
- If
return_type == True
Field names and the corresponding InfluxDB field types as a pair of lists of strings. The possible types are:
integer
,float
,string
andboolean
.
- If
Note
Returns an empty list if the query does not return any vaues, for example, if there are no tags in the series or if there is no series with the given name.
- get_keys(series, tag)¶
Get list of all tag values for a given tag in a series.
- Parameters
series (str) – Name of the series.
tag (str) – Name of the tag.
- Return type
list[str]
- Returns
List of all values of the tag in the series.
Note
Returns an empty list if the query does not return any vaues, for example, if there are no tags in the series or if there is no series with the given name.
- get_data(series, fields, keys=None, start=None, stop=None, local_tz=False)¶
Get data (records) for specified fields/tags in a series.
- Parameters
series (str) – Name of the series.
fields (str|list[str]|tuple[str]|set[str]|dict[str: str|type]) –
Name(s) of fields/tags in the series. This parameter is treated differently depending on it’s type:
str
Treated as a single field/tag name to return. If
fields
='*'
then all fields and tags are returned.list[str]
,tuple[str]
orset[str]
Treated as a collection of field/tag names to return.
dict[str: str|type]
The keys are treated as field/tag names, and the values are treated as numpy types (or names of numpy types) of the corresponding keys.
The output is converted from InfluxDB types to the types specified in the dictionary.
Use
None
as a field type to enable type autodetection and/or avoid type conversion for that field.
keys (None|dict[str: obj], optional) –
Dictionary providing rules to select records with specific field/tag values, defaults to
None
.If
None
then selected records are not filtered. Otherwise the dictionary is treated as follows:- Key
Name of the filtered field/tag.
- Values
Value(s) of the corresponding field/tag to be selected.
Each value can be a scalar or a collection of all values to be selected (
list
,tuple
orset
)
start (None|str|int|datetime, optional) –
Inclusive lower time boundary for the returned data, defaults to
None
.None
indicates no lower boundary.str
is interpreted as a timestring.int
is interpreted as a Unix timestamp.datetime
is used as is.stop (None|str|int|datetime, optional) –
Exclusive upper time boundary for the returned data, defaults to
None
.None
indicates no upper boundary.str
is interpreted as a timestring.int
is interpreted as a Unix timestamp.datetime
is used as is.local_tz (bool, optional) – Indicates whether local or UTC time is used in the code, defaults to
False
(UTC).
- Return type
dict[str: np.array]
- Returns
Dictionary constructed as follows:
- Key
Field/tag name.
- Value
Numpy array of the corresponding field/tag values.
- class chronobiology.chronobiology.CycleAnalyzer(timestamps, activity=None, night=None, step='1m', start=None, stop=None, descr='', max_gap='1m', min_duration='1m', min_activity=1, min_data_points=1)¶
Class to calculate and plot circadian cycles data.
- Variables
start (np.datetime64) – Adjusted lower time boundary (inclusive) of data included in analysis. Due to start time adjustment it might differ from 00:00:00 but it’s guaranteed that
self.start
belongs to the same day (date) as thestart
argument passed during the class initialization (or that it falls in the same day as the first timestamp in thetimestamps
argument ifstart
isNone
).stop (np.datetime64) – Adjusted upper time boundary (exclusive) of data included in analysis. Due to start time adjustion it might differ from 00:00:00 but it’s guaranteed that
self.stop
is no less than thestop
argument passed during the class initialization and thatself.stop - self.start
is equal to the whole number of days.step (np.timedelta64) – Same as the constructor argument.
steps_per_day (int) – Numbers of steps (bins) in a day.
descr (str) – Same as the constructor argument.
total_days (int) – Total number of days (including filtered out) between the
start
andstop
timestamps.days (int) – Number of days not filtered out due to low activity.
vartype – Mask calculated from data and
min_data_points
. Array of length equal tototal_days
. HoldsTrue
for the days that weren’t filtered out due to low activity andFalse
for those that were.min_data_points (int) – Same as the constructor argument.
max_gap (np.timedelta64) – Same as the constructor argument, but converted to
np.timedelta64[m]
(minute precision).min_duration (np.timedelta64) – Same as the constructor argument, but converted to
np.timedelta64[m]
(minute precision).min_activity (int) – Same as the constructor argument.
- Parameters
timestamps (np.array[np.timedelta64]) – Timestamps of activity records.
activity (None|np.array[int|float], optional) – Activity events (weights) associated with each timestamp. If not specified then it’s assumed that
activity
=1
for each timestamp.night (None|np.array[bool], optional) –
Boolean array denoting timestamps associated with night. The i-th timestamp is associated with night if
night[i]
=True
and with day otherwise. If not specified then it’s assumed thatnight
=True
for each timestamp.Note
When binning, if there are conflicting values for
night
in a bin (timestamps with bothnight
=True
andnight
=False
fall into the same bin) thennight
=True
is written for that bin (i.e.True
values overrideFalse
values in the same bin).step (str|int|timedelta, optional) – Discretization step, defaults to
'1m'
. All data is discretized by binning it into bins of this size.start (None|str|int|datetime, optional) – Lower time boundary (inclusive) for processed records, defaults to
None
.None
indicates no lower boundary.stop (None|str|int|datetime, optional) – Upper time boundary (exclusive) for processed records, defaults to
None
.None
indicates no upper boundary.descr (str, optional) – Textual description appended to the end of plot headers, defaults to
''
. Used to specify the source of data on the plots.max_gap (str|int|timedelta, optional) – Maximal gap between two consecutive activity events, defaults to
'1m'
. Consecutive events with distance between them larger thanmax_gap
belong to different activity bouts.min_duration (str|int|timedelta, optional) – Minimal duration of activity bout, defaults to
'1m'
. Activity bouts with shorter duration (defined as the time difference between the last activity event in a bout and the first one) are discarded.min_activity (int, optional) – Minimal value of (binned) activity, defaults to
1
. Bins with activity less thanmin_activity
are discarded during activity bout calculations. For example, ifself.step
='5 min'
andmin_activity
=6
then the data is binned into 5 minute bins, and during the activity bout calculation, bins withactivity
<6
are treated as if there is no activity within their intervals.min_data_points (int, optional) – Minimum number of data points (records) in a day, defaults to
1
. Days with fewer data points (records) are filtered out.
Properties
Timestamps of activity records.
Activity events associated with each timestamp.
Boolean array denoting the timestamps associated with night.
Precalculated bouts to be used in class methods when
bouts=True
is passed to them.Methods
Calculate activity bouts using provided parameters.
Re-calculate and update
self.bouts
using provided parameters.Re-filter days based on a new minimal daily number of data points.
Plot double actogram with right half shifted by 1 day.
Calculate periodogram for the range of periods.
Calculate and plot
periodogram()
for the range of periods.Calculate light phase activity.
Calculate and plot
light_activity()
for each day.Calculate interdaily stability.
Calculate intradaily variability.
Calculate and plot
intradaily_variability()
for each day.Calculate relative amplitude.
Calculate and plot
relative_amplitude()
for each day.Calculate daily activity bout statistics.
Calculate and plot
daily_bouts()
statistics.Plot histogram of
activity_bouts()
duration distribution.Calculate activity onset for each day.
Calculate and plot
activity_onset()
for each day.Note
Most methods can base their analysis on either number of activity events or precalculated activity bouts.
Note
Methods accepting timespan parameters (e.g.
start
,min_duration
and all other parameters of typestr|int|timedelta
) can treet them differently depending on their type:str
parameters are parsed like timedelta strings (e.g.'03:43:40'
),int
parameters are treated as the number of nanoseconds,timedelta
parameters are treated as they are.- property timestamps¶
Timestamps of activity records.
- Type
np.array[np.datetime64]
- Returns
Bin starts (discrete time points). Days with number of data points less than
min_data_points
are not included.
- property activity¶
Activity events associated with each timestamp.
- Type
np.array[int|float]
- Returns
Activity values for each bin. Days with the number of data points less than
min_data_points
are not included.
Activity value for each bin is equal to the sum of activity values for input data point that fall into this bin.
- property night¶
Boolean array denoting the timestamps associated with night.
The i-th timestamp is associated with night if
night[i]
=True
and with day otherwise.- Type
np.array[bool]
- Returns
Filtered night values for each bin. Days with the number of data points less than
min_data_points
are not included.
- property bouts¶
Precalculated bouts to be used in class methods when
bouts=True
is passed to them.- Type
np.array[int]
- Returns
Bouts list.
- activity_bouts(max_gap=None, min_duration=None, min_activity=None)¶
Calculate activity bouts using provided parameters.
Discretization step is taken from the constructor (
self.step
).Warning
Do not update
self.bouts
manually, callupdate_bouts()
instead.- Parameters
max_gap (None|str|int|timedelta, optional) – Overrides
self.max_gap
if specified.min_duration (None|str|int|timedelta, optional) – Overrides
self.min_duration
if specified.min_activity (None|int, optional) – Overrides
self.min_activity
if specified.
- Return type
np.array[int]
- Returns
Array holding 1 for steps that belong to some activity bout and 0 otherwise. Consecutive 1’s in bouts belong to the same bout.
- update_bouts(max_gap=None, min_duration=None, min_activity=None)¶
Re-calculate and update
self.bouts
using provided parameters.Also updates
max_gap
,min_duration
andmin_activity
if they are notNone
.Discretization step is taken from class initialization time (
self.step
).- Parameters
max_gap (None|str|int|timedelta, optional) – Overrides
self.max_gap
if specified.min_duration (None|str|int|timedelta, optional) – Overrides
self.min_duration
if specified.min_activity (None|int, optional) – Overrides
self.min_activity
if specified.
- filter_inactive(min_data_points=1)¶
Re-filter days based on a new minimal daily number of data points.
- Parameters
min_data_points (int, optional) – Minimum number of data points (records) in a day, defaults to
1
. Days with fewer data points (records) are filtered out.
- plot_actogram(step=None, bouts=False, log=False, activity_onset='step', percentile=20, N='6h', M='6h', filename=None, width=1000, height=100, dpi=100)¶
Plot double actogram with right half shifted by 1 day.
Night intervals for each day are also plotted on actogram as well as activity onset for each day.
- Parameters
step (None|str|int|timedelta, optional) – Bin size (the number of bars in actogram is equal to [24 hours] / step), defaults to
None
.None
stands forself.max_gap
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.log (bool, optional) – Indicates whether the log of activity is plotted, defaults to
False
. Has no effect ifbouts
=True
.activity_onset (None|False|str, optional) – Shape of the convolution kernel to use for activity onset calculation, defaults to
'step'
. To turn the activity onset display off passNone
,False
or string'none'
(case-insensitive). Otherwise it must be one of the strings recognized byself.activity_onset()
.percentile (int, optional) – Percentile of the daily non-zero activity to use as a threshold for activity onset calculation, defaults to
20
. Activity lower than that is treated as a zero activity.N (str|int|timedelta, optional) – Length of the period of negative values (daytime, left part) in the convolution kernel for activity onset calculation, defaults to
'6h'
.M (str|int|timedelta, optional) – Length of the period of positive values (nighttime, right part) in the convolution kernel for activity onset calculation, defaults to
'6h'
.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 100.
dpi (int, optional) – Plot resolution, defaults to 100.
- periodogram(step=None, min_period='16h', max_period='32h', bouts=False)¶
Calculate periodogram for the range of periods.
If
periods, powers = periodogram()
thenperiods[powers.argmax()]
returns the period with the maximal periodogram power.- Parameters
step (None|str|int|timedelta, optional) – Step size for the generating periods. The first period has a length of
min_period
, the second period has a length ofmin_period + step
and so on.None
stands forself.max_gap
.min_period (str|int|timedelta, optional) – Minimal period length, inclusive, defaults to
'16h'
.max_period (str|int|timedelta, optional) – Maximal period length, inclusive, defaults to
'32h'
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.
- Return type
(np.array[np.timedelta64], np.array[float])
- Returns
(periods, powers)
whereperiods
is periods in the range frommin_period
tomax_period
(inclusive).powers
is the corresponding periodogram powers for each period.
- plot_periodogram(step=None, min_period='16h', max_period='32h', bouts=False, filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
periodogram()
for the range of periods.The plot also includes an indication of the period with the maximal periodogram power.
- Parameters
step (None|str|int|timedelta, optional) – Step size for the generating periods. The first period has a length of
min_period
, the second period has a length ofmin_period + step
and so on.None
stands forself.max_gap
.min_period (str|int|timedelta, optional) – Minimal period length, inclusive, defaults to
'16h'
.max_period (str|int|timedelta, optional) – Maximal period length, inclusive, defaults to
'32h'
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- light_activity(bouts=False, auc=False)¶
Calculate light phase activity.
- Parameters
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.auc (bool, optional) – Flag to return AUC, defaults to
False
.
- Return type
(np.array[float], float)|(np.array[float], float, float)
- Returns
(daily_values, total)
or(daily_values, total, auc_val)
ifauc
=True
wheredaily_values
is the relative amplitude for each day;total
is the relative amplitude calculated from the data for all days;auc_val
is the area under the curve (integral).
- plot_light_activity(bouts=False, filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
light_activity()
for each day.The plot also includes total value based on data for all days.
- Parameters
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- interdaily_stability(step='1h', bouts=False)¶
Calculate interdaily stability.
Note
Small step values lead to high interdaily variability even with stable activity patterns.
- Parameters
step (None|str|int|timedelta, optional) – Data discretization step used for calculations, defaults to
None
.None
stands forself.max_gap
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.
- Return type
float
- Returns
Number from 0 to 1 (inclusive).
- intradaily_variability(step='1h', bouts=False, auc=False)¶
Calculate intradaily variability.
Note
Small step values lead to high interdaily variability even with stable activity patterns.
- Parameters
step (None|str|int|timedelta, optional) – Data discretization step used for calculations, defaults to
None
.None
stands forself.max_gap
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.auc (bool, optional) – Flag to return AUC, defaults to
False
.
- Return type
(np.array[float], float)|(np.array[float], float, float)
- Returns
(daily_values, total)
or(daily_values, total, auc_val)
ifauc
=True
wheredaily_values
is the relative amplitude for each day;total
is the relative amplitude calculated from the data for all days;auc_val
is the area under the curve (integral).
- plot_intradaily_variability(step='1h', bouts=False, filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
intradaily_variability()
for each day.The plot also includes the total value based on data for all days.
- Parameters
step (None|str|int|timedelta, optional) – Data discretization step used for calculations, defaults to
None
.None
stands forself.max_gap
.bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- relative_amplitude(most_active='10h', least_active='5h', bouts=False, auc=False)¶
Calculate relative amplitude.
- Parameters
most_active (str|int|timedelta, optional) – Length of the most active period.
least_active (str|int|timedelta, optional) – Length of the least active period.
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.
- Return type
(np.array[float], float)|(np.array[float], float, float)
- Returns
(daily_values, total)
or(daily_values, total, auc_val)
ifauc
=True
wheredaily_values
is the relative amplitude for each day;total
is the relative amplitude calculated from the data for all days;auc_val
is the area under the curve (integral).
- plot_relative_amplitude(most_active='10h', least_active='5h', bouts=False, filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
relative_amplitude()
for each day.The plot also includes the total value based on data for all days.
- Parameters
most_active (str|int|timedelta, optional) – Length of the most active period.
least_active (str|int|timedelta, optional) – Length of the least active period.
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- daily_bouts(max_gap=None, min_duration=None, min_activity=None)¶
Calculate daily activity bout statistics.
At first it calculates activity bouts based on provided parameters and then for each day, it calculates the number of activity bouts and the average activity bout duration.
- Parameters
max_gap (None|str|int|timedelta, optional) – Overrides
self.max_gap
if specified.min_duration (None|str|int|timedelta, optional) – Overrides
self.min_duration
if specified.min_activity (None|int, optional) – Overrides
self.min_activity
if specified.
- Return type
(np.array[int], np.array[float])
- Returns
(bout_counts, bout_durations)
wherebout_counts
is the number of activity bouts in each day;bout_durations
is the average activity bout durations for each day in minutes.
- plot_daily_bouts(max_gap=None, min_duration=None, min_activity=None, filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
daily_bouts()
statistics.Bout counts are plotted as a bar plot vs left y-axis and average bout durations are plotted as a line plot vs right y-axis.
- Parameters
max_gap (None|str|int|timedelta, optional) – Overrides
self.max_gap
if specified.min_duration (None|str|int|timedelta, optional) – Overrides
self.min_duration
if specified.min_activity (None|int, optional) – Overrides
self.min_activity
if specified.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- plot_bout_histogram(max_gap=None, min_duration=None, min_activity=None, bins=50, filename=None, width=1000, height=600, dpi=100)¶
Plot histogram of
activity_bouts()
duration distribution.- Parameters
max_gap (None|str|int|timedelta, optional) – Overrides
self.max_gap
if specified.min_duration (None|str|int|timedelta, optional) – Overrides
self.min_duration
if specified.min_activity (None|int, optional) – Overrides
self.min_activity
if specified.bins (int|np.array[int], optional) – Number of bins or array of bin edges.
filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- activity_onset(step=None, percentile=20, N='6h', M='6h', bouts=False, mode='step')¶
Calculate activity onset for each day.
Activity onset for a given day is calculated as follows:
Split the day into intervals of a uniform length (discretize it with some step).
Denote all points where activity is less than the percentile of non-zero activity as being inactive.
Set activity values of all inactive points to -1 and all other points to 1.
Apply the convolution kernel with the left part being negative and the right part being positive to the activity values. This will smoothly summarize the activity values.
Find the point with the maximal summarized value. This will be the activity onset.
- Parameters
step (None|str|int|timedelta, optional) – Data discretization step used for calculations, defaults to
None
.None
stands forself.max_gap
.percentile (int, optional) – Percentile of the daily non-zero activity to use as a threshold for activity onset calculation. Activity lower than that is treated as a zero activity.
N (str|int|timedelta, optional) – Length of the period of negative values (daytime, left part) in the convolution kernel for activity onset calculation.
M (str|int|timedelta, optional) – Length of the period of positive values (nighttime, right part) in the convolution kernel for activity onset calculation.
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.mode (str, optional) –
Defines the shape of the convolution kernel. Each kernel has a discontinuity where left and righ parts connect (the values around the discontinuity are -1 and 1 for the left and right parts respectively). For kernels other than step the left part is decreasing from 0 to -1 and the right part is decreasing from 1 to 0, i.e. the parts of the kernel further from the discontinuity are given less weight.
The possible kernels are:
'step'
– function with uniform left and right parts.'linear'
– linear function of the relative distance to the discontinuity.'quadratic'
– quadratic function (square root) of the relative distance to the discontinuity.'sine'
– function proportional to a shifted sine (cosine) of the relative distance to the discontinuity.
- Return type
np.array[np.datetime64]
- Returns
Activity onsets for each day.
Note
The returned array contains timestamps (absolute time values of an activity onset), not relative shifts from the start of the day.
- plot_activity_onset(step=None, percentile=20, N='6h', M='6h', bouts=False, mode='step', filename=None, width=1000, height=600, dpi=100)¶
Calculate and plot
activity_onset()
for each day.Activity onsets for each day are plotted as shifts (in hours) from the start of the day (the maximal possible value is 24).
- Parameters
step (None|str|int|timedelta, optional) – Data discretization step used for calculations, defaults to
None
.None
stands forself.max_gap
.percentile (int, optional) – Percentile of the daily non-zero activity to use as a threshold for activity onset calculation. Activity lower than that is treated as a zero activity.
N (str|int|timedelta, optional) – Length of the period of negative values (daytime, left part) in the convolution kernel for activity onset calculation.
M (str|int|timedelta, optional) – Length of the period of positive values (nighttime, right part) in the convolution kernel for activity onset calculation.
bouts (bool, optional) – Indicates that the calculation is based on the number of activity bouts rather then activity events, defualts to
False
.mode (str, optional) –
Defines the shape of the convolution kernel. Each kernel has a discontinuity where left and righ parts connect (the values around the discontinuity are -1 and 1 for the left and right parts respectively). For kernels other than step the left part is decreasing from 0 to -1 and the right part is decreasing from 1 to 0, i.e. the parts of the kernel further from the discontinuity are given less weight.
The possible kernels are:
'step'
– function with uniform left and right parts.'linear'
– linear function of the relative distance to the discontinuity.'quadratic'
– quadratic function (square root) of the relative distance to the discontinuity.'sine'
– function proportional to a shifted sine (cosine) of the relative distance to the discontinuity.filename (None|str|PathLike, optional) – Name of the file where the graph is saved. If not specified then the graph is displayed on the screen.
width (int, optional) – Plot width in pixels, defaults to 1000.
height (int, optional) – Plot height in pixels, defaults to 600.
dpi (int, optional) – Plot resolution, defaults to 100.
- chronobiology.chronobiology.generate_data(points_per_day=100, days=10, activity_period='24h', night_period='24h', bg_ratio=0.2, multiactivity=False)¶
Generate random input data.
- Parameters
points_per_day (int) – Number of measurement points per day, defaults to
100
.days (int) – Series length in days, defaults to
10
.activity_period (str|int|timedelta) – Activity period length, defaults to
'24h'
.night_period (str|int|timedelta) – Period of night, defaults to
'24h'
.bg_ratio (float) – Backgraoud activity ratio, defaults to
0.2
.multiactivity (bool) – Multiactivity, defaults to
False
.
- Return type
dict[str: np.array[np.datetime64]|np.array[float]|np.array[bool]]
- Returns
Dictionary containing arrays
'time'
,'value'
and'is_night'
ready to be used as input for theCycleAnalyzer
constructor.
Usage example
>>> data = generate_data() >>> ca = CycleAnalyzer(data['time'], data['value'], data['is_night'])
- chronobiology.chronobiology.generate_night(timeseries, night_period='24h')¶
Generate a random
is_night
array.- Parameters
timeseries (np.array[np.datetime64]) – Timestamps of measurements.
night_period (str|int|timedelta, optional) – Period of night, defualts to
'24h'
.
- Return type
np.array[bool]
- Returns
Array denoting whether night (
True
) or day (False
) is associated with a corresponding measurement.