Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyActigraphy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@
"viz"
]

__version__ = '1.2.2'
__version__ = '1.2.3'
2 changes: 2 additions & 0 deletions pyActigraphy/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .dqt import read_raw_dqt
from .mesa import read_raw_mesa
from .mtn import read_raw_mtn
from .nsrr import read_raw_nsrr
from .rpx import read_raw_rpx
from .tal import read_raw_tal

Expand All @@ -32,6 +33,7 @@
"read_raw_dqt",
"read_raw_mesa",
"read_raw_mtn",
"read_raw_nsrr"
"read_raw_rpx",
"read_raw_tal"
]
11 changes: 11 additions & 0 deletions pyActigraphy/io/nsrr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Module to read generic NSRR files."""

# Author: Grégory Hammad <gregory.hammad@uliege.be>
#
# License: BSD (3-clause)

from .nsrr import RawNSRR

from .nsrr import read_raw_nsrr

__all__ = ["RawNSRR", "read_raw_nsrr"]
238 changes: 238 additions & 0 deletions pyActigraphy/io/nsrr/nsrr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import pandas as pd
import os
import warnings

from ..base import BaseRaw
from pyActigraphy.light import LightRecording


class RawNSRR(BaseRaw):
r"""Raw object from generic NSRR files

Parameters
----------
input_fname: str
Path to the NSRR file.
time_origin: datetime-like
Time origin of the timestamps.
Required as the NSRR files do not contain date informations.
Default is '2000-01-01'
start_time: datetime-like, optional
Read data from this time.
Default is None.
period: str, optional
Length of the read data.
Cf. #timeseries-offset-aliases in
<https://pandas.pydata.org/pandas-docs/stable/timeseries.html>.
Default is None (i.e all the data).
intervals: dict, optional
Map manually annotated periods to specific scores.
If set to None, the names of the annotated periods is returned instead.
Default is {'EXCLUDED': -1, 'ACTIVE': 1, 'REST': 0.5, 'REST-S': 0}.
check_dayofweek: bool, optional
If set to True, check if the day of the week reported in the original
recoring is aligned with the reconstructed index.
Default is False.
"""

def __init__(
self,
input_fname,
time_origin='2000-01-01',
start_time=None,
period=None,
intervals={'EXCLUDED': -1, 'ACTIVE': 1, 'REST': 0.5, 'REST-S': 0},
check_dayofweek=False
):

# get absolute file path
input_fname = os.path.abspath(input_fname)

# read file
data = pd.read_csv(input_fname, index_col='line')

# extract informations from the header
name = data.iloc[1, 0]

# set additional informations manually
uuid = None
freq = pd.Timedelta(30, unit='s')

# day of the week
self.__dayofweek = data['dayofweek']

# reconstruct NSRR datetime index
date = pd.to_datetime(
data['daybymidnight'] - 1 + data.loc[1, 'dayofweek'],
unit='D',
origin=time_origin
).astype(str)
time = data['linetime']

index = pd.DatetimeIndex(date + ' ' + time, freq='infer')

data.set_index(index, inplace=True)

if check_dayofweek:
# Shift day of the week to match Pandas' convention (0=Monday, etc)
dw = self.__dayofweek - 2
if (data.index.dayofweek - dw.where(dw >= 0, dw + 7)).sum() != 0:
warnings.warn((
"Specified time_origin is such that the day of the week in"
" the reconstructed time index is *not* aligned with the"
" day of the week reported in the recording."
))

# set start and stop times
if start_time is not None:
start_time = pd.to_datetime(start_time)
else:
start_time = data.index[0]

if period is not None:
period = pd.Timedelta(period)
stop_time = start_time+period
else:
stop_time = data.index[-1]
period = stop_time - start_time

data = data[start_time:stop_time]

# no wear indicator
self.__nowear = data['offwrist']

# event marker indicator
self.__marker = data['marker']

# LIGHT
self.__white_light = data['whitelight']
self.__red_light = data['redlight']
self.__green_light = data['greenlight']
self.__blue_light = data['bluelight']

# wake indicator
self.__wake = data['wake']

# intervals
if intervals is not None:
self.__intervals = data['interval'].map(intervals)
else:
self.__intervals = data['interval']

# call __init__ function of the base class
super().__init__(
fpath=input_fname,
name=name,
uuid=uuid,
format='NSRR',
axial_mode='tri-axial',
start_time=start_time,
period=period,
frequency=freq,
data=data['activity'],
light=LightRecording(
name=name,
uuid=uuid,
data=data.loc[:, [
'whitelight', 'redlight', 'greenlight', 'bluelight'
]
],
frequency=data.index.freq
)
)

@property
def marker(self):
r"""Event marker indicator."""
return self.__marker

@property
def wake(self):
r"""Awake indicator."""
return self.__wake

@property
def nowear(self):
r"""Off-wrist indicator."""
return self.__nowear

@property
def intervals(self):
r"""Interval type (manual rest-activty scoring)."""
return self.__intervals

@property
def dayofweek(self):
r"""Day of the week (1=Sunday, 2=Monday, etc)."""
return self.__dayofweek

@property
def white_light(self):
r"""Value of the white light illuminance in lux."""
return self.__white_light

@property
def red_light(self):
r"""Value of the light intensity in µw/cm²."""
return self.__red_light

@property
def green_light(self):
r"""Value of the light intensity in µw/cm²."""
return self.__green_light

@property
def blue_light(self):
r"""Value of the light intensity in µw/cm²."""
return self.__blue_light


def read_raw_nsrr(
input_fname,
time_origin='2000-01-01',
start_time=None,
period=None,
intervals={'EXCLUDED': -1, 'ACTIVE': 1, 'REST': 0.5, 'REST-S': 0},
check_dayofweek=False
):
r"""Reader function for generic NSRR files

Parameters
----------
input_fname: str
Path to the ActTrust file.
time_origin: datetime-like
Time origin of the timestamps.
Required as the NSRR files do not contain date informations.
Default is '2000-01-01'
start_time: datetime-like, optional
Read data from this time.
Default is None.
period: str, optional
Length of the read data.
Cf. #timeseries-offset-aliases in
<https://pandas.pydata.org/pandas-docs/stable/timeseries.html>.
Default is None (i.e all the data).
intervals: dict, optional
Map manually annotated periods to specific scores.
If set to None, the names of the annotated periods is returned instead.
Default is {'EXCLUDED': -1, 'ACTIVE': 1, 'REST': 0.5, 'REST-S': 0}.
check_dayofweek: bool, optional
If set to True, check if the day of the week reported in the original
recoring is aligned with the reconstructed index.
Default is False.

Returns
-------
raw : Instance of RawNSRR
An object containing raw NSRR data
"""

return RawNSRR(
input_fname=input_fname,
time_origin=time_origin,
start_time=start_time,
period=period,
intervals=intervals,
check_dayofweek=check_dayofweek
)
7 changes: 6 additions & 1 deletion pyActigraphy/io/reader/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..dqt import read_raw_dqt
from ..mesa import read_raw_mesa
from ..mtn import read_raw_mtn
from ..nsrr import read_raw_nsrr
from ..rpx import read_raw_rpx
from ..tal import read_raw_tal
from pyActigraphy.log import read_sst_log
Expand Down Expand Up @@ -238,6 +239,7 @@ def read_raw(
* DQT (Daqtometers, Daqtix)
* MESA (MESA dataset, NSRR)
* MTN (MotionWatch8, CamNtech)
* NSRR (generic file, NSRR)
* RPX (Actiwatch, Respironics)
* TAL (Tempatilumi, CE Brasil)

Expand All @@ -262,7 +264,7 @@ def read_raw(
"""

supported_types = [
'AGD', 'ATR', 'AWD', 'BBA', 'DQT', 'MESA', 'MTN', 'RPX', 'TAL'
'AGD', 'ATR', 'AWD', 'BBA', 'DQT', 'MESA', 'MTN', 'NSRR', 'RPX', 'TAL'
]
if reader_type not in supported_types:
raise ValueError(
Expand Down Expand Up @@ -302,6 +304,9 @@ def parallel_reader(
'MTN': lambda files: parallel_reader(
n_jobs, read_raw_mtn, files, prefer, verbose, **kwargs
),
'NSRR': lambda files: parallel_reader(
n_jobs, read_raw_nsrr, files, prefer, verbose, **kwargs
),
'RPX': lambda files: parallel_reader(
n_jobs, read_raw_rpx, files, prefer, verbose, **kwargs
),
Expand Down