Source code for entry_exit_mouse_box.results_table

from qtpy.QtWidgets import (QWidget, QVBoxLayout, QPushButton, QApplication, QMainWindow,
                            QTableWidget, QTableWidgetItem, QFileDialog)
from PyQt5.QtGui import QColor, QFont
import numpy as np
import csv


[docs] class ResultsTable(QMainWindow): def __init__(self, data, name='Data Table', parent=None): super(ResultsTable, self).__init__(parent) self.exp_name = "untitled.csv" self.setWindowTitle(name) self.font = QFont() self.font.setFamily("Arial Unicode MS, Segoe UI Emoji, Apple Color Emoji, Noto Color Emoji") self.init_ui() self.set_data(data)
[docs] def init_ui(self): # Central widget self.centralWidget = QWidget(self) self.setCentralWidget(self.centralWidget) # Layout self.layout = QVBoxLayout(self.centralWidget) # Table self.table = QTableWidget() self.layout.addWidget(self.table) # Add table to layout # Export Button self.exportButton = QPushButton('💾 Save as CSV') self.exportButton.setFont(self.font) self.exportButton.clicked.connect(self.export_data) self.layout.addWidget(self.exportButton)
[docs] def set_data(self, data): # Assume we have some data structure holding CSV-like data columnHeaders = ['Column 1', 'Column 2', 'Column 3'] rowHeaders = ['Row 1', 'Row 2'] rowData = [['Row1-Col1', 'Row1-Col2', 'Row1-Col3'], ['Row2-Col1', 'Row2-Col2', 'Row2-Col3']] self.table.setColumnCount(len(columnHeaders)) self.table.setRowCount(len(rowData)) self.table.setHorizontalHeaderLabels(columnHeaders) self.table.setVerticalHeaderLabels(rowHeaders) for row, data in enumerate(rowData): for column, value in enumerate(data): item = QTableWidgetItem(value) # Set background color for the cell item.setBackground(QColor(255, 255, 200)) # Light yellow background self.table.setItem(row, column, item)
[docs] def set_exp_name(self, name): self.exp_name = ".".join(name.replace(" ", "-").split('.')[:-1]) + ".csv"
[docs] def export_data(self): options = QFileDialog.Options() try: fileName, _ = QFileDialog.getSaveFileName( self, "QFileDialog.getSaveFileName()", self.exp_name, "CSV Files (*.csv);;All Files (*)", options=options ) except: fileName = None if not fileName: print("No file selected") self.export_table_to_csv(self.table, fileName)
[docs] def export_table_to_csv(self, tableWidget: QTableWidget, filename: str): # Open a file in write mode with open(filename, 'w', newline='', encoding='utf-8') as file: writer = csv.writer(file, delimiter=';') # Writing headers (optional) headers = [tableWidget.horizontalHeaderItem(i).text() if tableWidget.horizontalHeaderItem(i) is not None else "" for i in range(tableWidget.columnCount())] writer.writerow(headers) # Writing data for row in range(tableWidget.rowCount()): row_data = [] for column in range(tableWidget.columnCount()): item = tableWidget.item(row, column) # Check if the cell is not empty if item is not None: row_data.append(item.text()) else: row_data.append('') writer.writerow(row_data)
# ====> The first result table contains the visibility and the centroid.
[docs] class FrameWiseResultsTable(ResultsTable): def __init__(self, data, parent=None): name = "visibility+centroids" super(FrameWiseResultsTable, self).__init__(data, name, parent) self.init_ui() self.set_data(data) print("Centroid and visibility table created")
[docs] def set_data(self, data): colors, centroids, visibility, box_names = data # Setting headers for each box. headers = ['Visibility', 'X', 'Y'] nHeaders = len(headers) columnHeaders = [] for name in box_names: for header in headers: columnHeaders.append(f'{header} ({name})') # Settings rows headers. rowHeaders = [str(i+1) for i in range(len(centroids))] self.table.setColumnCount(len(columnHeaders)) self.table.setRowCount(len(rowHeaders)) self.table.setHorizontalHeaderLabels(columnHeaders) self.table.setVerticalHeaderLabels(rowHeaders) # Filling the table. for frame in range(len(centroids)): # For each frame for box in range(len(box_names)): v_str = "" v = visibility[box][frame] if v < 0: v_str = "" elif v == 0: v_str = "Hidden" else: v_str = "Visible" c = centroids[frame][box] color = QColor(colors[box][0], colors[box][1], colors[box][2], 100) item_v = QTableWidgetItem(v_str) item_x = QTableWidgetItem(str(round(c[0], 2)) if c[0] >= 0.0 else "") item_y = QTableWidgetItem(str(round(c[1], 2)) if c[0] >= 0.0 else "") item_v.setBackground(color) item_x.setBackground(color) item_y.setBackground(color) self.table.setItem(frame, box * nHeaders + 0, item_v) self.table.setItem(frame, box * nHeaders + 1, item_x) self.table.setItem(frame, box * nHeaders + 2, item_y) self.table.resizeColumnsToContents()
# ====> The second result table contains the session data (session time, session distance)
[docs] class SessionsResultsTable(ResultsTable): def __init__(self, data, parent=None): name = "sessions" super(SessionsResultsTable, self).__init__(data, name, parent) self.init_ui() self.set_data(data) print("Sessions table created")
[docs] def set_data(self, data): colors_raw, in_out_count, sessions, box_names, visibility, unit = data colors = [QColor(int(colors_raw[box_index][0]), int(colors_raw[box_index][1]), int(colors_raw[box_index][2]), 100) for box_index in range(len(box_names))] # Setting headers for each box. # First frame of the session, duration of the session, number of go in/go out for this box headers = ['First frame', 'Duration (s)', f'Distance ({unit})'] status = ['V', 'H'] last = '#I/O' nHeaders = len(box_names) * len(headers) * len(status) + len(box_names) # Searching for the maximum number of sessions. max_sessions = int(np.ceil(float(np.max(in_out_count)) / 2.0)) + 1 # Settings rows headers. rowHeaders = [" ", " "] + [str(i+1) for i in range(max_sessions)] self.table.setColumnCount(nHeaders) self.table.setRowCount(len(rowHeaders)) self.table.setVerticalHeaderLabels(rowHeaders) # From the first item of visibility, we determine if the first session is hidden or visible. # 1 for visible, 0 for hidden. sessions_location = [-1 for i in range(len(box_names))] for box_idx in range(len(box_names)): for i in range(len(visibility[box_idx])): if visibility[box_idx][i] >= 0: sessions_location[box_idx] = visibility[box_idx][i] break # Filling the headers nBoxHeaders = len(headers) * len(status) + 1 for box_index in range(len(box_names)): box_header = [box_names[box_index]] + [" " for i in range(nBoxHeaders-1)] color = colors[box_index] for i in range(nBoxHeaders): item = QTableWidgetItem(box_header[i]) item.setBackground(color) self.table.setItem(0, nBoxHeaders * box_index + i, item) for s_i, s_t in enumerate(status): for h_i, h_t in enumerate(headers): item = QTableWidgetItem(f"[{s_t}] {h_t}") item.setBackground(color) self.table.setItem(1, nBoxHeaders * box_index + s_i * len(headers) + h_i, item) item = QTableWidgetItem(last) item.setBackground(color) self.table.setItem(1, nBoxHeaders * box_index + nBoxHeaders - 1, item) # Filling the table. last_pos_by_column = [2 for i in range(len(box_names)*nBoxHeaders)] for session_idx in range(np.max(in_out_count)): for box_idx in range(len(box_names)): color = colors[box_idx] # (frame_start, duration (s), duration (f), distance) session = sessions[box_idx][session_idx] try: f_frame = int(session[0]) except: continue session_visibility = visibility[box_idx][int(session[0])] shift = 0 if session_visibility > 0 else 1 duration = round(session[1], 2) col_index = nBoxHeaders * box_idx + shift * len(headers) item = QTableWidgetItem(str(f_frame)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index], col_index, item) item = QTableWidgetItem(str(duration)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+1], col_index+1, item) item = QTableWidgetItem(str(round(session[3], 2))) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+2], col_index+2, item) last_pos_by_column[col_index] += 1 last_pos_by_column[col_index+1] += 1 last_pos_by_column[col_index+2] += 1 # Filling the last column with the number of go in/out. for box_idx in range(len(box_names)): color = colors[box_idx] item = QTableWidgetItem(str(in_out_count[box_idx])) item.setBackground(color) self.table.setItem(2, nBoxHeaders * box_idx + nBoxHeaders - 1, item) self.table.resizeColumnsToContents()
[docs] def read_names(f_path): descr = open(f_path, "r") content = descr.read() descr.close() box_names = content.split(";") return box_names
[docs] def main_sessions(): from time import sleep visibility = np.squeeze(np.load("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/visibility.npy")) in_out_count = np.squeeze(np.load("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/in_out_count.npy")) sessions = np.squeeze(np.load("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/sessions.npy")) centroids = np.squeeze(np.load("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/centroids.npy")) colors = np.squeeze(np.load("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/colors.npy")) box_names = read_names("/home/benedetti/Documents/projects/25-entry-exit-mouse-monitor/tmp/box_names.txt") app = QApplication([]) table = SessionsResultsTable((colors, in_out_count, sessions, box_names, visibility, "px")) table.set_exp_name("Nom de manip.mp4") table.show() app.exec_() print("DONE.")
if __name__ == '__main__': main_sessions()