Skip to content

Commit 2a14844

Browse files
author
argon
committed
.
1 parent bbf30ef commit 2a14844

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed
16 KB
Binary file not shown.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
2+
import os
3+
import pandas as pd
4+
import plotly.graph_objects as go
5+
import logging
6+
# Set up logging
7+
logging.basicConfig(level=logging.INFO)
8+
logger = logging.getLogger(__name__)
9+
10+
class NewGroup:
11+
def __init__(self):
12+
self.obs_path = "/Shared/vosslabhpc/Projects/BOOST/ObservationalStudy/3-experiment/data/act-obs-test"
13+
self.int_path = "/Shared/vosslabhpc/Projects/BOOST/InterventionStudy/3-experiment/data/act-int-test"
14+
15+
self.paths = [
16+
os.path.join(self.obs_path, 'derivatives', 'GGIR-3.2.6-test-ncp-sleep'),
17+
os.path.join(self.int_path, 'derivatives', 'GGIR-3.2.6-test-ncp-sleep')
18+
]
19+
20+
self.path = './plots'
21+
22+
23+
def _parse_person_file(self, file_path):
24+
try:
25+
df = pd.read_csv(file_path)
26+
sleep = df["dur_spt_min_pla"].iloc[0]
27+
inactivity = df["dur_day_total_IN_min_pla"].iloc[0]
28+
light = df["dur_day_total_LIG_min_pla"].iloc[0]
29+
mod = df["dur_day_total_MOD_min_pla"].iloc[0]
30+
vig = df["dur_day_total_VIG_min_pla"].iloc[0]
31+
mvpa = mod + vig
32+
total = sleep + inactivity + light + mvpa
33+
logger.debug(f"Parsed {file_path}: sleep={sleep}, inactivity={inactivity}, light={light}, mvpa={mvpa}, total={total}")
34+
if total == 0:
35+
logger.warning(f"Total was 0 for {file_path}. Columns found: {df.columns.tolist()}")
36+
return None
37+
if df.empty:
38+
logger.warning(f"{file_path} is empty.")
39+
return None
40+
return {
41+
"Sleep": sleep / total * 1440,
42+
"Inactivity": inactivity / total * 1440,
43+
"Light": light / total * 1440,
44+
"MVPA": mvpa / total * 1440
45+
}
46+
except Exception as e:
47+
logger.warning(f"Error reading file {file_path}: {e}")
48+
return None
49+
50+
51+
def plot_person(self):
52+
durations = []
53+
54+
for base_dir in self.paths:
55+
for entry in sorted(os.listdir(base_dir)):
56+
if not entry.startswith("sub-"):
57+
continue
58+
59+
person_file = os.path.join(
60+
base_dir, entry, "accel", "output_accel", "results",
61+
"part5_personsummary_MM_L40M100V400_T5A5.csv"
62+
)
63+
64+
if not os.path.isfile(person_file):
65+
logger.debug(f"File not found for {entry}, skipping.")
66+
continue
67+
68+
values = self._parse_person_file(person_file)
69+
if not values:
70+
continue
71+
72+
values["Subject"] = entry
73+
durations.append(values)
74+
75+
df_all = pd.DataFrame(durations)
76+
if not df_all.empty and "Subject" in df_all.columns:
77+
df_all = df_all[~df_all["Subject"].str.startswith("sub-6")].reset_index(drop=True)
78+
df_all = df_all.sort_values("Subject").reset_index(drop=True)
79+
else:
80+
logger.warning("No valid data found — skipping Subject filtering.")
81+
82+
self._plot_stacked_bar(df_all,
83+
title="Normalized Average Activity Composition by Subject (All Sessions)",
84+
filename="avg_plot_all.html")
85+
def plot_session(self):
86+
durations = []
87+
88+
for base_dir in self.paths:
89+
for entry in sorted(os.listdir(base_dir)):
90+
if not entry.startswith("sub-"):
91+
continue
92+
93+
subject_path = os.path.join(base_dir, entry, "accel")
94+
if not os.path.isdir(subject_path):
95+
continue
96+
97+
for session_folder in sorted(os.listdir(subject_path)):
98+
if not session_folder.startswith("ses"):
99+
continue
100+
101+
person_file = os.path.join(
102+
subject_path,
103+
session_folder,
104+
f"output_{session_folder}",
105+
"results",
106+
"part5_personsummary_MM_L40M100V400_T5A5.csv"
107+
)
108+
109+
if not os.path.isfile(person_file):
110+
logger.debug(f"Missing file for {entry}/{session_folder}, skipping.")
111+
continue
112+
113+
values = self._parse_person_file(person_file)
114+
if not values:
115+
continue
116+
117+
values["Subject"] = entry
118+
values["Session"] = session_folder
119+
durations.append(values)
120+
121+
df_all = pd.DataFrame(durations)
122+
if not df_all.empty and "Subject" in df_all.columns and "Session" in df_all.columns:
123+
df_all = df_all[~df_all["Subject"].str.startswith("sub-6")].reset_index(drop=True)
124+
df_all = df_all.sort_values(["Session", "Subject"]).reset_index(drop=True)
125+
else:
126+
logger.warning("No valid data found — skipping Subject/Session filtering.")
127+
128+
for session, group_df in df_all.groupby("Session"):
129+
self._plot_stacked_bar(
130+
group_df,
131+
title=f"Average Activity Composition — Session {session.upper()}",
132+
y_key="Subject",
133+
filename=f"avg_plot_{session}.html"
134+
)
135+
def _plot_stacked_bar(self, df, title, filename, y_key="Subject"):
136+
if df.empty:
137+
logger.warning("No data to plot.")
138+
return
139+
140+
activities = ["Sleep", "Inactivity", "Light", "MVPA"]
141+
colors = {
142+
"Sleep": "#A8DADC",
143+
"Inactivity": "#F1FAEE",
144+
"Light": "#FFD6A5",
145+
"MVPA": "#FF9F1C"
146+
}
147+
148+
fig = go.Figure()
149+
for activity in activities:
150+
fig.add_trace(go.Bar(
151+
y=df[y_key],
152+
x=df[activity],
153+
name=activity,
154+
orientation='h',
155+
marker_color=colors[activity],
156+
hovertemplate=df[y_key] + f" - {activity} = " +
157+
(df[activity] / 60).round(2).astype(str) + " hr<extra></extra>"
158+
))
159+
160+
fig.update_layout(
161+
barmode='stack',
162+
title=title,
163+
xaxis=dict(title="Hours (normalized to 24)"),
164+
yaxis=dict(title=y_key),
165+
height=30 * len(df),
166+
margin=dict(l=20, r=20, t=40, b=20),
167+
showlegend=True,
168+
autosize=True
169+
)
170+
os.makedirs(self.path, exist_ok=True)
171+
fig.write_html(os.path.join(self.path, filename))

0 commit comments

Comments
 (0)