Skip to content

Commit 1f27741

Browse files
committed
add ecg plot of each suspicious zone
1 parent 207a840 commit 1f27741

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

src/ecg_analysis/analyze_ecg.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ def analyze(rrfile, ecgfile, locfile=None, axislimit=DEFAULT_AXIS_LIMIT, thresho
8484
fig, ax = plt.subplots(3, 1, figsize=(24, 12), layout="constrained", sharex=True)
8585
ax[0].xaxis.grid(True)
8686
ax[0].yaxis.grid(True)
87-
ax[0].scatter(time_p,rr_p,marker='x')
87+
ax[0].scatter(time_p, rr_p, marker='x')
8888
ax[0].set_ylabel("RR(msec)", fontsize=12)
8989
ax[1].xaxis.grid(True)
9090
ax[1].yaxis.grid(True)
91-
ax[1].plot(time_p,sigma_p)
91+
ax[1].plot(time_p, sigma_p)
9292
ax[1].set_ylabel("SDΔRR(msec)", fontsize=12)
9393
ax[2].xaxis.grid(True)
9494
ax[2].yaxis.grid(True)
95-
ax[2].plot(ecgtime,ecguv)
95+
ax[2].plot(ecgtime, ecguv)
9696
ax[2].set_xlabel("time", fontsize=12)
9797
ax[2].set_ylabel(R"ECG($\mu$v)", fontsize=12)
9898
ax[0].set_title(f"{rrfile}, {ecgfile}", fontsize=14)
@@ -112,7 +112,7 @@ def analyze(rrfile, ecgfile, locfile=None, axislimit=DEFAULT_AXIS_LIMIT, thresho
112112
# fig, ax = plt.subplots(1, 1, figsize=(24, 12), layout="constrained", sharex=True)
113113
# ax.xaxis.grid(True)
114114
# ax.yaxis.grid(True)
115-
# ax.plot(time_p,sigma_p)
115+
# ax.plot(time_p, sigma_p)
116116
# ax.set_xlabel("time", fontsize=12)
117117
# ax.set_ylabel("SDΔRR(msec)", fontsize=12)
118118
# #ax.scatter(list(range(len(sigma_l))), sigma_l, marker='+', c='r')
@@ -123,11 +123,11 @@ def analyze(rrfile, ecgfile, locfile=None, axislimit=DEFAULT_AXIS_LIMIT, thresho
123123
warn = np.insert(warn, 0, False)
124124
warn = np.append(warn, False)
125125
indices = np.nonzero(np.diff(warn))[0]
126-
warns = np.reshape(indices, (int(len(indices)/2),2))
126+
warns = np.reshape(indices, (int(len(indices)/2), 2))
127127
time_pn = time_p.to_numpy()
128128
durations = np.diff(time_pn[warns])/np.timedelta64(1, 's')
129129
longds = durations >= 20
130-
qualified_warn_indices_p =warns[longds[:,0]]
130+
qualified_warn_indices_p =warns[longds[:, 0]]
131131
if len(qualified_warn_indices_p) > 0:
132132
print("Suspicious events found in " + rrfile, file=sys.stderr)
133133

@@ -138,22 +138,46 @@ def analyze(rrfile, ecgfile, locfile=None, axislimit=DEFAULT_AXIS_LIMIT, thresho
138138

139139
figno = 0
140140
for w in qualified_warn_indices_p:
141+
141142
wstart = time_p[w[0]]
142143
wend = time_p[w[1]]
143144
deltat = (wend - wstart) / np.timedelta64(1, 's')
144145
print(f"warning from {wstart} to {wend}, duration {deltat} seconds.")
145146

147+
# plot the RR, SDΔRR, ecg waveforms in the zone
148+
ecguv_subset = ecguv[np.logical_and(ecgtime>= wstart, ecgtime <= wend)]
149+
ecgtime_subset = ecgtime[np.logical_and(ecgtime>= wstart, ecgtime <= wend)]
150+
fig, ax = plt.subplots(3, 1, figsize=(24, 12), layout="constrained", sharex=True)
151+
ax[0].xaxis.grid(True)
152+
ax[0].yaxis.grid(True)
153+
ax[0].scatter(time_p[w[0]:w[1]], rr_p[w[0]:w[1]], marker='x')
154+
ax[0].set_ylabel("RR(msec)", fontsize=12)
155+
ax[1].xaxis.grid(True)
156+
ax[1].yaxis.grid(True)
157+
ax[1].plot(time_p[w[0]:w[1]], sigma_p[w[0]:w[1]])
158+
ax[1].set_ylabel("SDΔRR(msec)", fontsize=12)
159+
ax[2].xaxis.grid(True)
160+
ax[2].yaxis.grid(True)
161+
ax[2].plot(ecgtime_subset, ecguv_subset)
162+
ax[2].set_xlabel("time", fontsize=12)
163+
ax[2].set_ylabel(R"ECG($\mu$v)", fontsize=12)
164+
ax[0].set_title(f"{rrfile}, {ecgfile}", fontsize=14)
165+
plt.savefig(ecgfile.replace(".csv", "") + "-" + str(figno) + ".png")
166+
plt.close(fig)
167+
168+
# update the zone in the location plot
146169
if locfile:
147170
lats = np.interp(time_p[w[0]:w[1]].to_numpy().view('int'), time_l.astype(int), latlon_l['lat'])
148171
lons = np.interp(time_p[w[0]:w[1]].to_numpy().view('int'), time_l.astype(int), latlon_l['lon'])
149-
subset = np.column_stack((lats,lons))
172+
ll_subset = np.column_stack((lats, lons))
150173

151-
folium.PolyLine(cleanll(subset), color="red").add_to(eventmap)
152-
folium.Circle(subset[0, :], color="red", fill=True, radius=10).add_to(eventmap)
153-
folium.Circle(subset[-1, :], color="green", fill=True, radius=10).add_to(eventmap)
174+
folium.PolyLine(cleanll(ll_subset), color="red").add_to(eventmap)
175+
folium.Circle(ll_subset[0, :], color="red", fill=True, radius=10).add_to(eventmap)
176+
folium.Circle(ll_subset[-1, :], color="green", fill=True, radius=10).add_to(eventmap)
154177

178+
# create a Poincaré plot for the zone
155179
fig, ax = plt.subplots(figsize=(10, 10), layout="constrained")
156-
rr_p_subset = rr_p[np.logical_and(time_p>= wstart, time_p <= wend)]
180+
rr_p_subset = rr_p[np.logical_and(time_p >= wstart, time_p <= wend)]
157181
x = rr_p_subset[0:-2]
158182
y = rr_p_subset[1:-1]
159183
ax.scatter(x, y)
@@ -176,14 +200,14 @@ def analyze(rrfile, ecgfile, locfile=None, axislimit=DEFAULT_AXIS_LIMIT, thresho
176200
ax.set_ylabel(r"$RR_{n+1}(msec)$", fontsize=12)
177201
ax.xaxis.grid(True)
178202
ax.yaxis.grid(True)
179-
180203
plt.savefig(rrfile.replace(".csv", "") + "-" + str(figno) + ".png")
181204
plt.close(fig)
182205

183206
figno += 1
184207

185-
if locfile:
186-
eventmap.save(locfile.replace(".csv", ".html"))
208+
# save the location plot with all zones updated
209+
if locfile:
210+
eventmap.save(locfile.replace(".csv", ".html"))
187211

188212
def main():
189213
parser = argparse.ArgumentParser(

0 commit comments

Comments
 (0)