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
import math

[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") return self.export_table_to_csv(fileName)
[docs] def export_table_to_csv(self, 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 = [self.table.horizontalHeaderItem(i).text() if self.table.horizontalHeaderItem(i) is not None else "" for i in range(self.table.columnCount())] writer.writerow(headers) # Writing data for row in range(self.table.rowCount()): row_data = [] for column in range(self.table.columnCount()): item = self.table.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, sessions, box_names, visibility, unit, fps = 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. # Time start of the session, duration of the session, number of go in/go out for this box headers = ['Time start (s)', 'Time start (f)', 'Duration (s)', 'Duration (f)', 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_count = max([sessions[box]['count'] for box in sessions.keys()]) max_sessions = int(1 + math.ceil(float(max_count) / 2.0)) # 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) # 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) last_pos_by_column = [2 for _ in range(len(box_names) * nBoxHeaders)] for box_idx in range(len(box_names)): s = sessions[box_idx]['sessions'] color = colors[box_idx] for session_idx, session in enumerate(s): start_frames = int(session['start']) start_seconds = round(start_frames / fps, 2) duration_frames = int(session['duration']) duration_seconds = round(duration_frames / fps, 2) distance = round(session['distance'], 2) visible = session['status'] shift = 0 if visible > 0 else 1 col_index = nBoxHeaders * box_idx + shift * len(headers) item = QTableWidgetItem(str(start_seconds)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+0], col_index+0, item) item = QTableWidgetItem(str(start_frames)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+1], col_index+1, item) item = QTableWidgetItem(str(duration_seconds)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+2], col_index+2, item) item = QTableWidgetItem(str(duration_frames)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+3], col_index+3, item) item = QTableWidgetItem(str(distance)) item.setBackground(color) self.table.setItem(last_pos_by_column[col_index+4], col_index+4, item) for i in range(5): last_pos_by_column[col_index+i] += 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(sessions[box_idx]['count'])) 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.load("/media/benedetti/5B0AAEC37149070F/mice-videos/2084-2086-2104-2106-T0.tmp//visibility.npy") sessions = 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.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, sessions, box_names, visibility, "px")) table.set_exp_name("Nom de manip.mp4") table.show() app.exec_() print("DONE.")
if __name__ == '__main__': main_sessions()