diff --git a/tools/predictive_indicators.py b/tools/predictive_indicators.py index c0a0c27836b9746a3fa556332f63859096365874..e90c19768380c288ce1ee0ff31362e21cfa1a4b6 100644 --- a/tools/predictive_indicators.py +++ b/tools/predictive_indicators.py @@ -12,7 +12,8 @@ import re from .database import Database from .processing import * from .plots import * -from time import time +from time import time, mktime +from datetime import datetime # %% - Constants QUERY_DROP_TABLE = lambda r: f"drop table if exists Robot{r}_indicators;" @@ -31,8 +32,13 @@ COMPUTED_COLUMS = [ # COMPUTED_COLUMS.append(f"{v}_A{m}") QUERY_INDICATORS = lambda r: f"SELECT * FROM Robot{r}_indicators;" +QUERY_ROBOTS = "SELECT DISTINCT `Robot` from DataFiles" + # %% - Computation for one run -def compute_run (DB: Database, robot: int, run: int, t0: int, date: str): +def compute_run (DB: Database, robot: int, run: int, t0: int, date: str, next: Callable[[str], None] = None): + + if next is not None: + next(f"Robot {robot} run n°{run} from {date}") out = [] @@ -43,6 +49,7 @@ def compute_run (DB: Database, robot: int, run: int, t0: int, date: str): data[data["MovingMotor"] == m] for m in range(1,7) ] + runTime = t0 + mktime(datetime.strptime(date, "%Y-%m-%d").timetuple()) # Compute for whole experiment # line = [ t0, 0 ] for m in range(1,7): @@ -51,7 +58,7 @@ def compute_run (DB: Database, robot: int, run: int, t0: int, date: str): temp = sub[f"Temperature_A{m}"].to_numpy() line = [ # *line, - t0, t0, 0, data["Class"][0], date, + runTime, runTime, 0, data["Class"][0], date, f"A{m}", RMS(c), kmeans(c), peak_factor(c), np.mean(temp) ] out.append(line) @@ -69,12 +76,13 @@ def compute_run (DB: Database, robot: int, run: int, t0: int, date: str): # line = [ time, s ] for m in range(1,7): sub = d[d["MovingMotor"] == m] - time = d["Sample_time"].to_numpy()[0] + t0 + time = d["Sample_time"].to_numpy()[0] + runTime c = sub[f"Current_A{m}"].to_numpy() temp = sub[f"Temperature_A{m}"].to_numpy() + line = [ # *line, - time, t0, s, data["Class"][0], date, + time, runTime, s, data["Class"][0], date, f"A{m}", RMS(c), kmeans(c), peak_factor(c), np.mean(temp) ] out.append(line) @@ -83,7 +91,7 @@ def compute_run (DB: Database, robot: int, run: int, t0: int, date: str): return out # %% - Transformation function -def compute_indicators (DB: Database, robot: int): +def compute_indicators (DB: Database, robot: int, next: Callable[[str], None] = None): if not (1 <= robot <= 3): print("Robot must be between 1 and 3") @@ -104,10 +112,24 @@ def compute_indicators (DB: Database, robot: int): out = [] for i, run in enumerate(runs): print("Robot", robot, "run n°", run) - out = [ *out, *compute_run(DB, robot, run, times[i], dates[i]) ] + out = [ *out, *compute_run(DB, robot, run, times[i], dates[i], next) ] # Save df = pd.DataFrame(out, columns=COMPUTED_COLUMS) df.to_sql(f"Robot{robot}_indicators", DB.db) return df + +#%% +def compute_indicators_all_robots (DB: Database, next: Callable[[str], None] = None): + + if (next is not None): + print("Has next function") + next("Initializing ...") + + robots: List[str] = pd.read_sql(QUERY_ROBOTS, DB.db)["Robot"].to_list() + for robot in robots: + print("Calculating indicators for", robot) + n = int(robot.split("_")[1]) + compute_indicators(DB, n, next) + \ No newline at end of file diff --git a/ui/Database.py b/ui/Database.py index b1d59e23236ccc2b42106eb9975aaae33c508687..7bcf83c488a720cb60fdf3ebe54319224f012c74 100644 --- a/ui/Database.py +++ b/ui/Database.py @@ -4,7 +4,10 @@ import PySimpleGUI as sg from pathlib import Path +from threading import Thread, Semaphore + from tools.database import Database, init_database +from tools.predictive_indicators import compute_indicators_all_robots from .DB_Metadata import DBFileManagerWindow class DBSelectWin (sg.Window): @@ -15,6 +18,14 @@ class DBSelectWin (sg.Window): self.edit_window = None + self.indicator_popup: sg.Window = None + self.indicator_popup_lock = Semaphore() + self.indicator_progress: int = 0 + self.indicator_max_progress: int = 0 + self.indicator_run_name: str = "None" + + self.db_use_done = False + super().__init__("Database Selector", self._layout(), finalize=True) self.update_display() @@ -25,7 +36,7 @@ class DBSelectWin (sg.Window): self.buttons = { "-open-close-": sg.Button("Open", key="-open-close-"), "-edit-": sg.Button("Edit Data", key="-edit-"), - "-plot-": sg.Button("Plot Data", key="-plot-"), + "-indicators-": sg.Button("Compute indicators", key="-indicators-"), "-new-": sg.Button("New Database", key="-new-"), "-browse-": sg.FileBrowse( key="-browse-", @@ -47,7 +58,7 @@ class DBSelectWin (sg.Window): [ self.buttons["-open-close-"], self.buttons["-edit-"], - self.buttons["-plot-"], + self.buttons["-indicators-"], sg.Push(), self.buttons["-new-"], ] @@ -63,14 +74,14 @@ class DBSelectWin (sg.Window): """ has_db = self.db is not None - using_data = (self.edit_window is not None) + using_data = (self.edit_window is not None) or (self.indicator_popup is not None) self.buttons["-edit-"].update( disabled=not has_db or using_data, button_color=sg.theme_button_color() ) - self.buttons["-plot-"].update( + self.buttons["-indicators-"].update( disabled=not has_db or using_data, button_color=sg.theme_button_color() ) @@ -96,6 +107,15 @@ class DBSelectWin (sg.Window): button_color=sg.theme_button_color() ) + self.indicator_popup_lock.acquire() + if self.indicator_popup is not None: + + self.indicator_popup["-run-name-"].update(value=self.indicator_run_name) + self.indicator_popup["-progress-"].update(current_count=self.indicator_progress) + + self.indicator_popup.read(1) + self.indicator_popup_lock.release() + def open_database (self, path: str): """Tries to open a Database @@ -154,6 +174,57 @@ class DBSelectWin (sg.Window): self.inputs["-db_path-"].update(value=text) self.open_database(text) + def compute_indicators (self): + + self.indicator_max_progress = len(self.db.list_files()) + 1 + self.indicator_progress = 0 + + popup = sg.Window("Computing indicators", [ + [ sg.Push(), sg.Text("Computing indicators."), sg.Push() ], + [ + sg.Push(), + sg.Text( + "This might take a while", + justification="center" + ), + sg.Push() + ], + [ + sg.Push(), + sg.Text("Waiting ...", key="-run-name-"), + sg.Push() + ], + [ + sg.ProgressBar(self.indicator_max_progress, expand_x=True, key="-progress-") + ] + ], finalize=True, disable_close=True, disable_minimize=True) + popup.read(1) + + self.indicator_popup = popup + + self.db.close() + + def compute_thread (self: DBSelectWin): + + def next (name: str): + print("Next", name) + self.indicator_popup_lock.acquire() + self.indicator_run_name = name + self.indicator_progress += 1 + self.indicator_popup_lock.release() + print("Released lock") + + self.db.open() + compute_indicators_all_robots(self.db, next) + self.db.close() + + self.indicator_popup_lock.acquire() + self.db_use_done = True + self.indicator_popup_lock.release() + + Thread(target=compute_thread, daemon=True, args=[self]).start() + + def poll (self): """Runs the window @@ -178,7 +249,19 @@ class DBSelectWin (sg.Window): self.edit_window.close() self.edit_window = None self.update_display() + + # DB management + self.indicator_popup_lock.acquire() + if self.db_use_done == True: + self.db_use_done = False + self.indicator_popup.close() + self.indicator_popup = None + self.db.open() + self.indicator_popup_lock.release() + # Update display + self.update_display() + return True # User opens the Database @@ -200,9 +283,10 @@ class DBSelectWin (sg.Window): self.edit_window = DBFileManagerWindow(self.db) # User wants to plot some data - if event == "-plot-": - pass + if event == "-indicators-": + self.compute_indicators() # Update this window display self.update_display() + return True