-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbatch_plot_uv.py
More file actions
84 lines (69 loc) · 3.05 KB
/
batch_plot_uv.py
File metadata and controls
84 lines (69 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""
Batch-plot optical-power CSV files.
Each CSV must have three columns:
1. ISO-8601 timestamp (YYYY-MM-DD HH:MM:SS)
2. Power in watts (blank rows mark UV-state changes)
3. UV state string ("ON" or "OFF" in rows that have blank power)
Usage
-----
$ python batch_plot_uv.py # assuming you save this as batch_plot_uv.py
"""
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
from pathlib import Path
def plot_one_csv(path: Path) -> None:
"""Read *path*, make the plot, show it, and save PNG next to the CSV."""
# -------------------- Load the CSV ------------------------------
raw = np.genfromtxt(path, delimiter=",", dtype=str, skip_header=1)
if raw.ndim == 1: # in case file has only one data row
raw = raw.reshape(1, -1)
ts_str, power_str, state_str = raw[:, 0], raw[:, 1], raw[:, 2]
data_mask = power_str != "" # rows carrying numeric power
# Guard against empty numeric section
if not data_mask.any():
print(f"[WARN] No numeric power rows found in {path.name}. Skipped.")
return
# -------------------- Time & power arrays -----------------------
t_datetimes = [datetime.fromisoformat(t) for t in ts_str[data_mask]]
t0 = t_datetimes[0]
t_elapsed_s = np.array([(t - t0).total_seconds() for t in t_datetimes])
power_mw = power_str[data_mask].astype(float) * 1_000.0 # W → mW
# -------------------- UV-state shading intervals ----------------
intervals, curr_state, curr_start = [], None, 0.0
for t_txt, st in zip(ts_str, state_str):
if st in ("ON", "OFF"):
t_now = (datetime.fromisoformat(t_txt) - t0).total_seconds()
if curr_state is not None:
intervals.append((curr_start, t_now, curr_state))
curr_state, curr_start = st, t_now
if curr_state is not None:
t_final = (datetime.fromisoformat(ts_str[-1]) - t0).total_seconds()
intervals.append((curr_start, t_final, curr_state))
# -------------------- Plot --------------------------------------
fig, ax = plt.subplots()
ax.plot(t_elapsed_s, power_mw, lw=1.0, label="Optical Power (mW)")
for start, end, st in intervals:
color = "lightgreen" if st == "ON" else "lightcoral"
ax.axvspan(start, end, facecolor=color, alpha=0.30)
ax.set_xlabel("Time (s)")
ax.set_ylabel("Optical Power (mW)")
title = f"Optical Power vs Time"
ax.set_title(title)
ax.legend()
plt.tight_layout()
# -------------------- Save & show -------------------------------
png_path = path.with_suffix(".png")
plt.savefig(png_path, dpi=300)
print(f"[OK] Saved: {png_path}")
plt.show() # remove if you don’t want interactive windows
def main():
csv_files = sorted(Path(".").glob("*.csv"))
if not csv_files:
print("[INFO] No CSV files found in the current directory.")
return
for f in csv_files:
print(f"[INFO] Processing {f.name}")
plot_one_csv(f)
if __name__ == "__main__":
main()