diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index ba3a463..e3466db 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -36,9 +36,11 @@ jobs: - name: Install Linux libraries if: runner.os == 'Linux' run: | + sudo apt-get update sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 \ libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ - libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 + libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 pkg-config libhdf5-103 libhdf5-dev \ + libegl1 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.gitignore b/.gitignore index e2a14af..3249732 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,7 @@ FaceMap/ops_user.npy *.sh *.pkl *.h5 - +*.mp4 # # ========================= # Operating System Files diff --git a/docs/installation.md b/docs/installation.md index 6fd565a..836b00a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -23,7 +23,7 @@ The software has been heavily tested on Ubuntu 18.04, and less well tested on Wi Facemap python relies on these awesome packages: - [pyqtgraph](http://pyqtgraph.org/) -- [PyQt5](http://pyqt.sourceforge.net/Docs/PyQt5/) +- [PyQt6](http://pyqt.sourceforge.net/Docs/PyQt6/) - [numpy](http://www.numpy.org/) (>=1.13.0) - [scipy](https://www.scipy.org/) - [opencv](https://opencv.org/) diff --git a/docs/installation.rst b/docs/installation.rst index 53e83f9..9025fac 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -28,7 +28,7 @@ Dependencies Facemap (python package) relies on these awesome packages: - `pyqtgraph`_ -- `pyqt5`_ +- `pyqt6`_ - `numpy`_ (>=1.13.0) - `scipy`_ - `opencv`_ @@ -40,7 +40,7 @@ Facemap (python package) relies on these awesome packages: - `UMAP`_ .. _pyqtgraph: http://pyqtgraph.org/ -.. _pyqt5: http://pyqt.sourceforge.net/Docs/PyQt5/ +.. _pyqt6: http://pyqt.sourceforge.net/Docs/PyQt6/ .. _numpy: http://www.numpy.org/ .. _scipy: https://www.scipy.org/ .. _opencv: https://opencv.org/ diff --git a/environment.yml b/environment.yml index eb9afe2..e48702f 100644 --- a/environment.yml +++ b/environment.yml @@ -16,7 +16,7 @@ dependencies: - torch>=1.9 - h5py - pyqtgraph>=0.12.0 - - pyqt5 - - pyqt5.sip + - qtpy + - pyqt6 - umap-learn diff --git a/facemap/.github/workflows/test_and_deploy.yml b/facemap/.github/workflows/test_and_deploy.yml index a9b61b6..1fb3ff4 100755 --- a/facemap/.github/workflows/test_and_deploy.yml +++ b/facemap/.github/workflows/test_and_deploy.yml @@ -36,9 +36,12 @@ jobs: - name: Install Linux libraries if: runner.os == 'Linux' run: | + sudo apt-get update sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 libxcb-icccm4 \ libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \ - libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 + libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 pkg-config libhdf5-103 libhdf5-dev \ + libegl1 libgl1 + sudo apt-get install '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev # strategy borrowed from vispy for installing opengl libs on windows - name: Install Windows OpenGL if: runner.os == 'Windows' diff --git a/facemap/gui/cluster.py b/facemap/gui/cluster.py index 28e2f04..8aaba8b 100644 --- a/facemap/gui/cluster.py +++ b/facemap/gui/cluster.py @@ -19,9 +19,9 @@ # import hdbscan from matplotlib import cm -from PyQt5 import QtCore, QtWidgets -from PyQt5.QtGui import QFont -from PyQt5.QtWidgets import ( +from qtpy import QtCore, QtWidgets +from qtpy.QtGui import QFont +from qtpy.QtWidgets import ( QButtonGroup, QCheckBox, QLabel, @@ -408,9 +408,9 @@ def run(self, clicked, parent): else: self.data_type = None msg = QMessageBox(parent) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Please select data for clustering") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() return if self.cluster_method == "UMAP": @@ -718,9 +718,9 @@ def ok_save(self, dialogBox, parent): pass else: msg = QMessageBox(parent) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Please generate cluster labels for saving cluster videos") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() if dialogBox.data_checkbox.isChecked(): self.save_cluster_output(parent) diff --git a/facemap/gui/gui.py b/facemap/gui/gui.py index 0c139c0..5981d87 100644 --- a/facemap/gui/gui.py +++ b/facemap/gui/gui.py @@ -5,22 +5,18 @@ import sys from pathlib import Path -import cv2 import h5py -import matplotlib import matplotlib.pyplot as plt import numpy as np import pyqtgraph as pg -import scipy.io as sio import torch from matplotlib import cm -from PyQt5 import QtCore, QtWidgets -from PyQt5.QtGui import QFont, QIcon, QPainterPath -from PyQt5.QtWidgets import ( +from qtpy import QtCore, QtWidgets, QtGui +from qtpy.QtGui import QFont, QIcon, QPainterPath +from qtpy.QtWidgets import ( QButtonGroup, QCheckBox, QComboBox, - QDesktopWidget, QFileDialog, QGridLayout, QGroupBox, @@ -125,18 +121,22 @@ def __init__( self.scene_grid_layout = QGridLayout() self.central_widget.setLayout(self.scene_grid_layout) # --- cells image - self.sizeObject = QDesktopWidget().screenGeometry(-1) + self.sizeObject = QtGui.QGuiApplication.primaryScreen().availableGeometry() self.resize(self.sizeObject.width(), self.sizeObject.height()) self.video_window = pg.GraphicsLayoutWidget() + self.video_window.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) + self.scene_grid_layout.addWidget(self.video_window, 0, 2, 5, 5) # Create a window for embedding and ROI plot self.roi_embed_window = pg.GraphicsLayoutWidget() + self.roi_embed_window.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.scene_grid_layout.addWidget(self.roi_embed_window, 0, 7, 5, 5) # Create a window for plots self.plots_window = pg.GraphicsLayoutWidget() + self.plots_window.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.scene_grid_layout.addWidget(self.plots_window, 5, 2, 4, 10) # A plot area (ViewBox + axes) for displaying the image @@ -833,17 +833,17 @@ def add_pose_model(self, pose_model_path=None): break # Display QMessage box to inform user that the model was successfully added msg = QMessageBox() - msg.setIcon(QMessageBox.Information) + msg.setIcon(QMessageBox.Icon.Information) msg.setText("Pose model successfully added.") msg.setWindowTitle("Pose model added") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() except Exception as e: msg = QMessageBox() - msg.setIcon(QMessageBox.Error) + msg.setIcon(QMessageBox.Icon.Critical) msg.setText("Pose model not added. Error: " + str(e)) msg.setWindowTitle("Eror") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() @@ -2255,7 +2255,7 @@ def load_video_popup(self): # Open a qmessage box to notify the user that the video is not loaded msg = QtWidgets.QMessageBox() # Error icon in the top left corner - msg.setIcon(QtWidgets.QMessageBox.Critical) + msg.setIcon(QtWidgets.QMessageBox.Icon.Critical) msg.setText("Please load a video first.") msg.setWindowTitle("No video loaded") msg.exec_() @@ -2269,16 +2269,16 @@ def invalid_trace_popup(self): def invalid_roi_popup(self): msg = QMessageBox(self) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("only pupil ROI allowed during online mode") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() def show_roi_selection_error(self): msg = QMessageBox(self) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Please select a ROI") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() def model_loaded_popup(self, model_path): diff --git a/facemap/gui/guiparts.py b/facemap/gui/guiparts.py index cccf832..0024771 100644 --- a/facemap/gui/guiparts.py +++ b/facemap/gui/guiparts.py @@ -3,8 +3,8 @@ """ import numpy as np import pyqtgraph as pg -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtWidgets import ( +from qtpy import QtCore, QtGui, QtWidgets +from qtpy.QtWidgets import ( QAbstractItemView, QButtonGroup, QDialog, @@ -232,7 +232,7 @@ class ImageDraw(pg.ImageItem): for controlling the levels and lookup table used to display the image. """ - sigImageChanged = QtCore.pyqtSignal() + sigImageChanged = QtCore.Signal() def __init__(self, image=None, viewbox=None, parent=None, **kargs): super(ImageDraw, self).__init__() diff --git a/facemap/gui/help_windows.py b/facemap/gui/help_windows.py index 46cecaf..fbd1fc0 100644 --- a/facemap/gui/help_windows.py +++ b/facemap/gui/help_windows.py @@ -5,11 +5,10 @@ import typing import numpy as np -from PyQt5 import QtCore -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPixmap -from PyQt5.QtWidgets import ( - QDesktopWidget, +from qtpy import QtCore +from qtpy.QtCore import Qt +from qtpy.QtGui import QPixmap, QGuiApplication +from qtpy.QtWidgets import ( QDialog, QGroupBox, QHBoxLayout, @@ -510,7 +509,7 @@ def __init__(self, gui, window_title): super().__init__(gui) self.gui = gui self.setWindowTitle(window_title) - window_size = QDesktopWidget().screenGeometry(-1) + window_size = QGuiApplication.primaryScreen().availableGeometry() self.setFixedSize( int(np.floor(window_size.width() * 0.31)), int(np.floor(window_size.height() * 0.31 * 0.5)), diff --git a/facemap/gui/io.py b/facemap/gui/io.py index f7e40e0..6b2a443 100644 --- a/facemap/gui/io.py +++ b/facemap/gui/io.py @@ -7,7 +7,7 @@ import numpy as np from natsort import natsorted -from PyQt5.QtWidgets import QFileDialog, QMessageBox +from qtpy.QtWidgets import QFileDialog, QMessageBox from facemap import roi, utils @@ -279,7 +279,7 @@ def get_folder_path(parent): else: # Open a qmessagebox to inform the user that the path does not exist msg = QMessageBox() - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("The path does not exist") msg.setWindowTitle("Warning") msg.exec_() @@ -367,7 +367,7 @@ def load_npy_file(parent, allow_mat=False): else: # Open a qmessagebox to inform the user that the path does not exist msg = QMessageBox() - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("The path does not exist") msg.setWindowTitle("Warning") msg.exec_() @@ -423,9 +423,9 @@ def load_cluster_labels(parent): return except Exception as e: msg = QMessageBox(parent) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Error: not a supported filetype") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() print(e) @@ -457,9 +457,9 @@ def load_umap(parent): return embedded_data except Exception as e: msg = QMessageBox(parent) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Error: not a supported filetype") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() print(e) @@ -480,9 +480,9 @@ def load_trace_data(parent): return dat except Exception as e: msg = QMessageBox(parent) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Error: not a supported filetype") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() print(e) diff --git a/facemap/gui/menus.py b/facemap/gui/menus.py index af2e7b6..3d5e8af 100644 --- a/facemap/gui/menus.py +++ b/facemap/gui/menus.py @@ -1,7 +1,8 @@ """ Copright © 2023 Howard Hughes Medical Institute, Authored by Carsen Stringer and Atika Syeda. """ -from PyQt5.QtWidgets import QAction, QDesktopWidget +from qtpy.QtWidgets import QAction +from qtpy.QtGui import QGuiApplication from . import help_windows, io @@ -116,8 +117,8 @@ def mainmenu(parent): def launch_user_manual(parent): - help_windows.MainWindowHelp(parent, QDesktopWidget().screenGeometry(-1)) + help_windows.MainWindowHelp(parent, QGuiApplication.primaryScreen().availableGeometry()) def show_about(parent): - help_windows.AboutWindow(parent, QDesktopWidget().screenGeometry(-1)) + help_windows.AboutWindow(parent, QGuiApplication.primaryScreen().availableGeometry()) diff --git a/facemap/gui/neural_activity_window.py b/facemap/gui/neural_activity_window.py index 4471900..0af7d81 100644 --- a/facemap/gui/neural_activity_window.py +++ b/facemap/gui/neural_activity_window.py @@ -5,9 +5,9 @@ import pyqtgraph as pg import scipy.io as sio from matplotlib import cm -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtCore import Qt, QUrl -from PyQt5.QtWidgets import * +from qtpy import QtCore, QtGui, QtWidgets +from qtpy.QtCore import Qt, QUrl +from qtpy.QtWidgets import * from facemap import utils from facemap.gui import guiparts, help_windows, io @@ -21,7 +21,7 @@ def __init__(self, parent=None, window_size=None): self.parent = parent # Set the size of the window if window_size is None: - self.sizeObject = QtWidgets.QDesktopWidget().screenGeometry(-1) + self.sizeObject = QtGui.QGuiApplication.primaryScreen().availableGeometry() else: self.sizeObject = window_size self.resize(np.floor(self.sizeObject.width() / 1.5).astype(int), np.floor(self.sizeObject.height() / 2).astype(int)) @@ -41,7 +41,7 @@ def __init__(self, parent=None, window_size=None): def center(self): qr = self.frameGeometry() - cp = QtWidgets.QDesktopWidget().availableGeometry().center() + cp = QtGui.QGuiApplication.primaryScreen().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) @@ -123,6 +123,7 @@ def setup_ui(self): # Add a plots window neural data visualization plots_window = pg.GraphicsLayoutWidget() + plots_window.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.neural_activity_plot = plots_window.addPlot( name="neural_activity_plot", row=0, col=0, title="Neural activity" @@ -305,7 +306,7 @@ def load_neural_predictions_file(self, neural_predictions_filepath=None): print("error", e) # Show error message msg = QtWidgets.QMessageBox() - msg.setIcon(QtWidgets.QMessageBox.Critical) + msg.setIcon(QtWidgets.QMessageBox.Icon.Critical) msg.setText("Invalid neural predictions file.") msg.setInformativeText( "The selected file is not a valid neural predictions file." @@ -599,7 +600,7 @@ def run_neural_predictions(self, clicked, dialog): if self.neural_activity.data is None: msg = QtWidgets.QMessageBox() - msg.setIcon(QtWidgets.QMessageBox.Critical) + msg.setIcon(QtWidgets.QMessageBox.Icon.Critical) msg.setText("Neural activity not loaded") msg.setInformativeText( "Please load neural activity data before running neural predictions" @@ -613,7 +614,7 @@ def run_neural_predictions(self, clicked, dialog): # Check if keypoints are loaded if self.parent.poseFilepath[0] is None: msg = QtWidgets.QMessageBox() - msg.setIcon(QtWidgets.QMessageBox.Critical) + msg.setIcon(QtWidgets.QMessageBox.Icon.Critical) msg.setText("Keypoints not loaded") msg.setInformativeText( "Please load keypoints before running neural predictions" @@ -687,7 +688,7 @@ def run_neural_predictions(self, clicked, dialog): x_input = self.movSVDs[0] except: msg = QtWidgets.QMessageBox() - msg.setIcon(QtWidgets.QMessageBox.Critical) + msg.setIcon(QtWidgets.QMessageBox.Icon.Critical) msg.setText("SVDs not loaded") msg.setInformativeText( "Please load SVDs (proc file) before running neural predictions" diff --git a/facemap/gui/ops_user.npy b/facemap/gui/ops_user.npy index 6082c5a..c538d1f 100755 Binary files a/facemap/gui/ops_user.npy and b/facemap/gui/ops_user.npy differ diff --git a/facemap/pose/model_training.py b/facemap/pose/model_training.py index fe14af3..34df575 100644 --- a/facemap/pose/model_training.py +++ b/facemap/pose/model_training.py @@ -55,7 +55,7 @@ def train( Whether to save the best model. The default is False. checkpoint_path : str, optional The path to save the best model. The default is None. - gui : PyQt5.QMainWindow + gui : qtpy.QMainWindow The main window of the application. gui_obj : QtWidgets The gui object of the application. diff --git a/facemap/pose/pose_gui.py b/facemap/pose/pose_gui.py index ba9d9d4..0a06fe7 100644 --- a/facemap/pose/pose_gui.py +++ b/facemap/pose/pose_gui.py @@ -4,9 +4,8 @@ import numpy as np import pyqtgraph as pg from matplotlib import cm -from PyQt5 import QtCore -from PyQt5.QtWidgets import ( - QDesktopWidget, +from qtpy import QtCore, QtGui, QtWidgets +from qtpy.QtWidgets import ( QDialog, QHBoxLayout, QPushButton, @@ -113,7 +112,7 @@ def adjust_bbox(self): class ROI_popup(QDialog): def __init__(self, frame, video_id, gui, pose, last_video): super().__init__() - window_max_size = QDesktopWidget().screenGeometry(-1) + window_max_size = QtGui.QGuiApplication.primaryScreen().availableGeometry() fraction = 0.5 aspect_ratio = 1.5 self.resize( @@ -129,6 +128,7 @@ def __init__(self, frame, video_id, gui, pose, last_video): # Add image and ROI bbox self.verticalLayout = QVBoxLayout(self) self.win = pg.GraphicsLayoutWidget() + self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.win.setObjectName("Dialog " + str(video_id + 1)) # fix image in ROI window ROI_win = self.win.addViewBox(invertY=True, lockAspect=True, enableMouse=False) @@ -233,6 +233,7 @@ def __init__(self, gui, video_id, pose, frame_idx, bodyparts): # Add image and pose prediction self.verticalLayout = QtWidgets.QVBoxLayout(self) self.win = pg.GraphicsLayoutWidget() + self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.win.setObjectName("Dialog " + str(video_id + 1)) frame_win = self.win.addViewBox(invertY=True) self.current_frame_idx = 0 diff --git a/facemap/pose/pose_helper_functions.py b/facemap/pose/pose_helper_functions.py index 13a7636..eab627d 100644 --- a/facemap/pose/pose_helper_functions.py +++ b/facemap/pose/pose_helper_functions.py @@ -12,8 +12,8 @@ import numpy as np import pyqtgraph as pg import torch # pytorch -from PyQt5 import QtWidgets -from PyQt5.QtWidgets import QDialog, QPushButton +from qtpy import QtWidgets, QtCore +from qtpy.QtWidgets import QDialog, QPushButton from scipy.ndimage import gaussian_filter # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Global variables~~~~~~~~~~~~~~~~~~~~~~~~~~~~~` @@ -248,6 +248,7 @@ def __init__(self, frame, gui, title="Test Popup"): # Add image and ROI bbox self.win = pg.GraphicsLayoutWidget() + self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) ROI_win = self.win.addViewBox(invertY=True) self.img = pg.ImageItem(self.frame) ROI_win.addItem(self.img) diff --git a/facemap/pose/refine_pose.py b/facemap/pose/refine_pose.py index 5c1ae9a..24caf4a 100644 --- a/facemap/pose/refine_pose.py +++ b/facemap/pose/refine_pose.py @@ -10,13 +10,12 @@ import pyqtgraph as pg import torch from matplotlib import cm -from PyQt5 import QtCore -from PyQt5.QtGui import QColor -from PyQt5.QtWidgets import ( +from qtpy import QtCore, QtGui +from qtpy.QtGui import QColor +from qtpy.QtWidgets import ( QButtonGroup, QCheckBox, QComboBox, - QDesktopWidget, QDialog, QFormLayout, QGridLayout, @@ -93,7 +92,7 @@ def __init__(self, gui): self.verticalLayout = QVBoxLayout(self) # Set window size that is adjusted to the size of the window - self.window_max_size = QDesktopWidget().screenGeometry(-1) + self.window_max_size = QtGui.QGuiApplication.primaryScreen().availableGeometry() self.show_choose_folder() self.setLayout(self.verticalLayout) @@ -106,6 +105,11 @@ def update_window_size(self, frac=0.5, aspect_ratio=1.0): int(np.floor(self.window_max_size.width() * frac)), int(np.floor(self.window_max_size.height() * frac * aspect_ratio)), ) + # center window on screen + centerPoint = QtGui.QGuiApplication.primaryScreen().availableGeometry().center() + qtRectangle = self.frameGeometry() + qtRectangle.moveCenter(centerPoint) + self.move(qtRectangle.topLeft()) def clear_window(self): # Clear the window @@ -174,13 +178,11 @@ def set_output_folder_path(self): ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Step 2: Choose training files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### def show_choose_training_files(self): - self.update_window_size(0.4, aspect_ratio=0.5) - self.output_folder_path = self.output_folder_path_box.text() # Check if path exists if not os.path.exists(self.output_folder_path): msg = QMessageBox(self) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setStyleSheet("QLabel{ color: white}") msg.setText("Please set a valid output folder path first") msg.setWindowTitle("Warning") @@ -472,6 +474,8 @@ def show_choose_training_files(self): ) self.verticalLayout.addWidget(self.buttons_groupbox) + + self.update_window_size(0.4, aspect_ratio=1.5) def show_data_files(self, yes_selected): """ @@ -640,11 +644,11 @@ def update_user_training_options(self): if self.output_model_name == "facemap_model_state": # Open a QMessageBox to warn the user that the model name is not allowed msg = QMessageBox(self) - msg.setIcon(QMessageBox.Warning) + msg.setIcon(QMessageBox.Icon.Warning) msg.setText("Output model name cannot be 'facemap_model_state'") msg.setStyleSheet("QLabel{ color: white}") msg.setWindowTitle("Warning") - msg.setStandardButtons(QMessageBox.Ok) + msg.setStandardButtons(QMessageBox.StandardButton.Ok) msg.exec_() return # Get the selected videos @@ -669,7 +673,7 @@ def show_step_3(self): else: # Show error message self.error_message = QMessageBox() - self.error_message.setIcon(QMessageBox.Critical) + self.error_message.setIcon(QMessageBox.Icon.Critical) self.error_message.setText("Please select at least one video for training.") self.error_message.setWindowTitle("Error") self.error_message.exec_() @@ -795,6 +799,7 @@ def show_refinement_options( self.frame_group = QGroupBox() self.frame_group.setLayout(QHBoxLayout()) self.win = pg.GraphicsLayoutWidget() + self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) self.win.setObjectName("Keypoints refinement") self.keypoints_scatterplot = KeypointsGraph(parent=self) self.frame_win = KeypointsViewBox( @@ -1338,6 +1343,7 @@ def visualize_model_predictions(self): for j in range(cols): frame = imgs[i * rows + j] self.win = pg.GraphicsLayoutWidget() + self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False) frame_win = self.win.addViewBox(invertY=True) frame_win.setAspectLocked(True) frame_win.addItem( diff --git a/facemap/roi.py b/facemap/roi.py index ba8b234..c8782ca 100644 --- a/facemap/roi.py +++ b/facemap/roi.py @@ -3,7 +3,7 @@ """ import numpy as np import pyqtgraph as pg -from PyQt5 import QtCore +from qtpy import QtCore from facemap import pupil, utils diff --git a/setup.py b/setup.py index 145b5d0..dbb2fec 100644 --- a/setup.py +++ b/setup.py @@ -21,8 +21,9 @@ ] gui_deps = [ "pyqtgraph>=0.12.0", - "pyqt5", - "pyqt5.sip", + "pyqt6", + "pyqt6.sip", + "qtpy", "matplotlib", ]