Scripts to create intensity plots from 24/7 accelerometer data
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.1 KiB

# -*- coding: utf-8 -*-
"""
Created on Wed Jun 16 09:34:35 2021
@author: -
"""
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import timedelta
from scipy.optimize import curve_fit
# Formulas
def ReadCSV(filename):
df = pd.read_csv(filename, names=['Datetime', 'Acc X','Acc Y', 'Acc Z'], infer_datetime_format=True)
df['Datetime'] = pd.to_datetime(df['Datetime'])
df['Date'] = [d.date() for d in df['Datetime']]
df = df.reindex(columns=['Datetime','Date','Time','Acc X','Acc Y', 'Acc Z'])
return df
def CreateDays(x, filename, path):
savename = filename.replace('.csv','')
savepath = path + savename
os.makedirs(savepath)
os.chdir(savepath)
startdate = x['Date'].iloc[0]
week = range(1,8)
for i in week:
weekdayindex = i-1
day = startdate + timedelta(days=weekdayindex)
daydate = x['Date'] == startdate + timedelta(days=weekdayindex)
dataday = x[daydate]
totalweek = {day:dataday}
savefile = totalweek[day]
varname = filename.replace('.csv','-') + str(day) + '.csv'
savefile.to_csv(varname)
print(varname +' saved')
return(totalweek)
def SVMEpoch(DF,ResampRate, ResampData):
newDF = pd.DataFrame(DF)
newDF['X2'] = np.power(newDF['Acc X'], 2)
newDF['Y2'] = np.power(newDF['Acc Y'], 2)
newDF['Z2'] = np.power(newDF['Acc Z'], 2)
newDF['SVM'] = np.sqrt(newDF[['X2', 'Y2', 'Z2']].sum(axis=1))
newDF['Datetime'] = pd.to_datetime(newDF['Datetime'])
EpochSVM = newDF.resample(ResampRate, on = ResampData).mean()
return(newDF, EpochSVM)
def func(x, a, b, c):
return a * np.exp(-b*x) + c
def SlopeWeeker(Keylist, Dict):
try:
SlopeWeek = pd.DataFrame(columns=['a','b', 'c', 'Name'])
SlopeWeek = SlopeWeek.set_index('Name')
for key in Keylist:
newDF, EpochSVM = SVMEpoch(Dict[key], '60S', 'Datetime')
ENMO = EpochSVM['SVM']-1
ENMO = ENMO*1000
for value in ENMO:
if value < 0:
value = 0
BinSize = 5
ENMOmax = int(ENMO.max())
if ENMOmax % BinSize == 0:
ENMOmax = ENMOmax+1 #to make sure that interference with binsize is impossible
MaxBin = int(ENMOmax/BinSize)+1
ENMO = ENMO.astype(int)
Counter = pd.DataFrame(np.zeros((1,MaxBin)))
for x in Counter:
Count = (x+1)*BinSize
Start = Count - BinSize
Number = ENMO.between(Start, Count).sum()
Counter[x] = Number
Counter = Counter.to_numpy()
Counter = Counter.astype(float)
Counter = Counter.flatten()
Xscale = np.arange(0,ENMOmax, BinSize)
Xscale = Xscale.astype(float)
popt, _ = curve_fit(func, Xscale, Counter, p0=None) # fit curve through points
a, b, c = popt
Trendline = func(Xscale, a, b, c)
SlopeWeek.loc[key, 'a'] = a
SlopeWeek.loc[key, 'b'] = b
SlopeWeek.loc[key, 'c'] = c
SlopeWeek.loc[key, 'ENMOmax'] = ENMOmax
PtName = key.replace('35694_00000', '')
PtName = PtName.replace('resampled-','')
PtName = PtName.replace('.csv','')
plt.figure(dpi=720)
plt.ylim(0,1440)
plt.xlim(0,(ENMOmax+10))
plt.title('Intensity plot ' + PtName)
plt.xlabel('Movement intensity [bins of ' + str(BinSize) + ' mg]')
plt.ylabel('Amount of time spend at intensity [min]')
plt.grid()
plt.scatter(Xscale, y=Counter)
plt.plot(Xscale, Trendline, 'r--')
PtName = (PtName + '.png')
plt.savefig(fname=PtName)
plt.show()
except:
print(PtName + ' could not be used')
return SlopeWeek