mantis-rtm 0.1.1.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env python3
2
+ import time
3
+ import argparse
4
+ import pandas as pd
5
+ import pathlib as pl
6
+ from watchdog.observers import Observer
7
+ from watchdog.events import FileSystemEventHandler
8
+
9
+ # Import project-specific modules
10
+ import mantis.plot_data_new as plot_data_new
11
+
12
+ class PlotUpdateHandler(FileSystemEventHandler):
13
+ """Handles file system events for the results CSV."""
14
+
15
+ def __init__(
16
+ self, csv_file, layout_file, display_length, measured_data, output_plot=None
17
+ ):
18
+ super().__init__()
19
+ self.csv_file = csv_file
20
+ self.layout_file = layout_file
21
+ self.display_length = display_length
22
+ self.measured_data = measured_data
23
+ self.output_plot = output_plot
24
+ self.last_trigger_time = 0
25
+ self.debounce_seconds = 1.0
26
+
27
+ def on_modified(self, event):
28
+ self._handle_event(event)
29
+
30
+ def on_created(self, event):
31
+ self._handle_event(event)
32
+
33
+ def on_moved(self, event):
34
+ self._handle_event(event)
35
+
36
+ def _handle_event(self, event):
37
+ if event.is_directory:
38
+ return
39
+
40
+ # Target files
41
+ target_csv = pl.Path(self.csv_file).resolve()
42
+ target_layout = pl.Path(self.layout_file).resolve()
43
+
44
+ # Source path of the event
45
+ src_path = pl.Path(event.src_path).resolve()
46
+ # For MoveEvent, we also check dest_path
47
+ dest_path = pl.Path(event.dest_path).resolve() if hasattr(event, 'dest_path') else None
48
+
49
+ is_match = (src_path == target_csv or src_path == target_layout or
50
+ (dest_path and (dest_path == target_csv or dest_path == target_layout)))
51
+
52
+ if is_match:
53
+ current_time = time.time()
54
+ dt = current_time - self.last_trigger_time
55
+ if dt > self.debounce_seconds:
56
+ print(f"[Monitor] DEBUG: Triggered by {event.event_type} on {src_path} (dt={dt:.3f}s)")
57
+ self.last_trigger_time = current_time
58
+ self.trigger_plot()
59
+ else:
60
+ # print(f"[Monitor] DEBUG: Debounced {event.event_type} on {src_path} (dt={dt:.3f}s)")
61
+ pass
62
+
63
+ def trigger_plot(self):
64
+ print(f"[Monitor] Change detected. Updating plots...")
65
+ try:
66
+ # Short sleep to ensure the file is fully written/closed by the simulation
67
+ time.sleep(0.5)
68
+
69
+ # Load the fresh data
70
+ df = pd.read_csv(self.csv_file)
71
+
72
+ # Use specified output name or derive from CSV
73
+ output_path = (
74
+ pl.Path(self.output_plot)
75
+ if self.output_plot
76
+ else pl.Path(self.csv_file).with_suffix(".pdf")
77
+ )
78
+
79
+ # Load layout (this allows updates to plot_layout.py to be picked up too)
80
+ plt_desc = plot_data_new.load_layout_from_file(df, self.layout_file, self.measured_data)
81
+
82
+ # Execute the plotting function as requested
83
+ plot_data_new.plot(
84
+ df,
85
+ self.display_length,
86
+ output_path,
87
+ show=False,
88
+ plot_description=plt_desc,
89
+ measured_data_path=self.measured_data,
90
+ )
91
+ print(f"[Monitor] Plots updated: {output_path.name}")
92
+
93
+ except Exception as e:
94
+ print(f"[Monitor] Error during plotting: {e}")
95
+
96
+
97
+ def main():
98
+ import sys
99
+
100
+ parser = argparse.ArgumentParser(
101
+ description="Monitor a CSV file and update plots automatically."
102
+ )
103
+ parser.add_argument(
104
+ "-f", "--file", default="pyrite_model_fipy.csv", help="CSV file to monitor"
105
+ )
106
+ parser.add_argument(
107
+ "-l", "--layout", default="plot_layout.py", help="Plot layout file"
108
+ )
109
+ parser.add_argument(
110
+ "-d",
111
+ "--display_length",
112
+ type=float,
113
+ default=2.0,
114
+ help="Display length in meters",
115
+ )
116
+ parser.add_argument("-m", "--measured", default=None, help="Measured data CSV file")
117
+ parser.add_argument(
118
+ "-o", "--output", help="Output plot filename (default: derived from --file)"
119
+ )
120
+
121
+ if len(sys.argv) == 1:
122
+ parser.print_help()
123
+ sys.exit(0)
124
+
125
+ args = parser.parse_args()
126
+
127
+ # Determine output path for the initial check
128
+ output_path = (
129
+ pl.Path(args.output) if args.output else pl.Path(args.file).with_suffix(".pdf")
130
+ )
131
+
132
+ # Setup the observer to watch the current directory
133
+ path = "."
134
+ event_handler = PlotUpdateHandler(
135
+ csv_file=args.file,
136
+ layout_file=args.layout,
137
+ display_length=args.display_length,
138
+ measured_data=args.measured,
139
+ output_plot=args.output,
140
+ )
141
+
142
+ # --- Initial Check ---
143
+ if not output_path.exists():
144
+ print(
145
+ f"[Monitor] Output file {output_path.name} not found. Generating initial plot..."
146
+ )
147
+ event_handler.trigger_plot()
148
+
149
+ observer = Observer()
150
+ observer.schedule(event_handler, path, recursive=False)
151
+
152
+ print(f"Starting Plot Monitor...")
153
+ print(f"Watching: {args.file}")
154
+ if args.output:
155
+ print(f"Output: {args.output}")
156
+ print(f"Layout: {args.layout}")
157
+ print(f"Display Length: {args.display_length}m")
158
+ print(f"Press Ctrl+C to stop.")
159
+
160
+ observer.start()
161
+ try:
162
+ while True:
163
+ time.sleep(1)
164
+ except KeyboardInterrupt:
165
+ print("\nStopping monitor...")
166
+ observer.stop()
167
+ observer.join()
168
+
169
+
170
+ if __name__ == "__main__":
171
+ main()