cbrnr / mnelab

MNELAB – a GUI for MNE
BSD 3-Clause "New" or "Revised" License
238 stars 69 forks source link

MNE Qt Browser does not work with MNELAB #401

Closed obergmartin closed 5 months ago

obergmartin commented 7 months ago

I'm using MNE 1.5.1 and MNELAB 0.8.6 with the [full] installation on a windows 11 workstation. I've loaded .vhdr and .fif files and can plot PSD and inspect channels in what looks like the normal qt windows. But I get the following error when trying plot data: Traceback (most recent call last): File "C:\Users\moberg\AppData\Local\mne-python\1.5.1_0\Lib\site-packages\mnelab\mainwindow.py", line 783, in plot_data win = fig.canvas.manager.window ^^^^^^^^^^ AttributeError: 'MNEQtBrowser' object has no attribute 'canvas' Also, after this error the toolbar icons are replaced with text description (that get cropped with ellipses ... ) What do I need to look into for trouble shooting?

cbrnr commented 7 months ago

Can you post a screenshot of the About dialog please?

obergmartin commented 7 months ago

Here they are: mnelab Capture_qt I should mention that everything works fine when I run MNE directly from my .py files. Thank you!

cbrnr commented 7 months ago

Can you upgrade to MNE 1.6.0 to see if this maybe fixes the problem?

obergmartin commented 7 months ago

Same problem, unfortunately (sorry for not looking at the requirements more closely before): Traceback (most recent call last): File "C:\Users\moberg\AppData\Local\mne-python\1.6.0_0\Lib\site-packages\mnelab\mainwindow.py", line 783, in plot_data win = fig.canvas.manager.window ^^^^^^^^^^ AttributeError: 'MNEQtBrowser' object has no attribute 'canvas' Capture-mnelab

cbrnr commented 7 months ago

I think the problem is the MNEQtBrowser backend, which is currently not supported. Can you switch to the Matplotlib backend meanwhile? You'd have to run the following two lines:

import mne
mne.set_config('MNE_BROWSER_BACKEND', 'matplotlib')
cbrnr commented 7 months ago

On macOS, the problem is even worse, because the app crashes 😢:

Using qt as 2D backend.
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(
        0   CoreFoundation                      0x000000018479c570 __exceptionPreprocess + 176
        1   libobjc.A.dylib                     0x000000018428deb4 objc_exception_throw + 60
        2   CoreFoundation                      0x0000000184712d10 -[__NSCFString hasSuffix:] + 0
        3   libqcocoa.dylib                     0x000000029e732044 _ZN20QCocoaSystemTrayIcon13emitActivatedEv + 274796
        4   libqcocoa.dylib                     0x000000029e7320c8 _ZN20QCocoaSystemTrayIcon13emitActivatedEv + 274928
        5   libqcocoa.dylib                     0x000000029e730688 _ZN20QCocoaSystemTrayIcon13emitActivatedEv + 268208
        6   QtWidgets                           0x000000012fa611a8 _ZN9QListView16selectionChangedERK14QItemSelectionS2_ + 204
        7   QtCore                              0x000000012dc1b48c _ZN11QMetaObject8activateEP7QObjectPKS_iPPv + 3808
        8   QtCore                              0x000000012dde1e44 _ZN19QItemSelectionModel20emitSelectionChangedERK14QItemSelectionS2_ + 216
        9   QtCore                              0x000000012dde1a2c _ZN19QItemSelectionModel6selectERK14QItemSelection6QFlagsINS_13SelectionFlagEE + 636
        10  QtCore                              0x000000012dde170c _ZN19QItemSelectionModel6selectERK11QModelIndex6QFlagsINS_13SelectionFlagEE + 68
        11  QtCore                              0x000000012dde28cc _ZN19QItemSelectionModel15setCurrentIndexERK11QModelIndex6QFlagsINS_13SelectionFlagEE + 260
        12  QtWidgets                           0x000000012f8bf338 _ZNK9QComboBox5countEv + 828
        13  QtWidgets                           0x000000012f8c28b4 _ZN9QComboBoxC1ER16QComboBoxPrivateP7QWidget + 2412
        14  QtCore                              0x000000012dc1b224 _ZN11QMetaObject8activateEP7QObjectPKS_iPPv + 3192
        15  QtCore                              0x000000012ddca944 _ZN18QAbstractItemModel13endInsertRowsEv + 200
        16  QtGui                               0x000000012f3577a4 _ZN18QStandardItemModel11itemChangedEP13QStandardItem + 2376
        17  QtWidgets                           0x000000012f8c5910 _ZN9QComboBox10insertItemEiRK5QIconRK7QStringRK8QVariant + 368
        18  QtWidgets.abi3.so                   0x000000012e59d3a8 _ZL25Sbk_QComboBoxFunc_addItemP7_objectS0_S0_ + 1032
        19  Python                              0x0000000105a89784 cfunction_call + 60
        20  Python                              0x0000000105a24d78 _PyObject_MakeTpCall + 128
        21  Python                              0x0000000105b4c06c _PyEval_EvalFrameDefault + 52804
        22  Python                              0x0000000105b519ec _PyEval_Vector + 156
        23  Python                              0x0000000105a25098 _PyObject_FastCallDictTstate + 96
        24  Python                              0x0000000105ab2754 slot_tp_init + 180
        25  Python                              0x0000000105aa90d8 type_call + 136
        26  Python                              0x0000000105a24d78 _PyObject_MakeTpCall + 128
        27  Python                              0x0000000105b4c06c _PyEval_EvalFrameDefault + 52804
        28  Python                              0x0000000105b519ec _PyEval_Vector + 156
        29  Python                              0x0000000105a25ba0 _PyVectorcall_Call + 160
        30  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        31  Python                              0x0000000105b519ec _PyEval_Vector + 156
        32  Python                              0x0000000105a25108 _PyObject_FastCallDictTstate + 208
        33  Python                              0x0000000105ab2754 slot_tp_init + 180
        34  Python                              0x0000000105aa90d8 type_call + 136
        35  Python                              0x0000000105a26034 _PyObject_Call + 124
        36  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        37  Python                              0x0000000105b519ec _PyEval_Vector + 156
        38  Python                              0x0000000105a25ba0 _PyVectorcall_Call + 160
        39  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        40  Python                              0x0000000105b519ec _PyEval_Vector + 156
        41  Python                              0x0000000105a25ba0 _PyVectorcall_Call + 160
        42  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        43  Python                              0x0000000105b519ec _PyEval_Vector + 156
        44  Python                              0x0000000105a25ba0 _PyVectorcall_Call + 160
        45  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        46  Python                              0x0000000105b519ec _PyEval_Vector + 156
        47  Python                              0x0000000105a25ba0 _PyVectorcall_Call + 160
        48  Python                              0x0000000105b4eb50 _PyEval_EvalFrameDefault + 63784
        49  Python                              0x0000000105b519ec _PyEval_Vector + 156
        50  Python                              0x0000000105a29158 method_vectorcall + 364
        51  libpyside6.abi3.6.6.dylib           0x00000001299b2750 _ZN6PySide13SignalManager20callPythonMetaMethodERK11QMetaMethodPPvP7_objectb + 536
        52  libpyside6.abi3.6.6.dylib           0x00000001299b2318 _ZN6PySide13SignalManager20SignalManagerPrivate16qtMethodMetacallEP7QObjectiPPv + 760
        53  QtCore                              0x000000012dc1b1f4 _ZN11QMetaObject8activateEP7QObjectPKS_iPPv + 3144
        54  QtGui                               0x000000012f3c70a4 _ZN7QAction8activateENS_11ActionEventE + 368
        55  QtWidgets                           0x000000012f8a8cf0 _ZNK15QAbstractButton11isCheckableEv + 344
        56  QtWidgets                           0x000000012f8a9c48 _ZN15QAbstractButton17mouseReleaseEventEP11QMouseEvent + 172
        57  QtWidgets                           0x000000012f9a7d90 _ZN11QToolButton17mouseReleaseEventEP11QMouseEvent + 20
        58  QtWidgets                           0x000000012f7f58b8 _ZN7QWidget5eventEP6QEvent + 132
        59  QtWidgets                           0x000000012f9a84ec _ZN11QToolButton5eventEP6QEvent + 208
        60  QtWidgets                           0x000000012f7ac594 _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent + 272
        61  QtWidgets                           0x000000012f7ae5c0 _ZN12QApplication6notifyEP7QObjectP6QEvent + 5072
        62  QtCore                              0x000000012dbd1474 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent + 292
        63  QtWidgets                           0x000000012f7acb34 _ZN19QApplicationPrivate14sendMouseEventEP7QWidgetP11QMouseEventS1_S1_PS1_R8QPointerIS0_Ebb + 808
        64  QtWidgets                           0x000000012f80a860 _ZNK21QWidgetRepaintManager3rhiEv + 11080
        65  QtWidgets                           0x000000012f809a6c _ZNK21QWidgetRepaintManager3rhiEv + 7508
        66  QtWidgets                           0x000000012f7ac594 _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent + 272
        67  QtWidgets                           0x000000012f7ad3e8 _ZN12QApplication6notifyEP7QObjectP6QEvent + 504
        68  QtCore                              0x000000012dbd1474 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent + 292
        69  QtGui                               0x000000012f0b39ec _ZN22QGuiApplicationPrivate17processMouseEventEPN29QWindowSystemInterfacePrivate10MouseEventE + 1740
        70  QtGui                               0x000000012f10f674 _ZN22QWindowSystemInterface22sendWindowSystemEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE + 408
        71  libqcocoa.dylib                     0x000000029e6d3d74 qt_plugin_instance + 58768
        72  CoreFoundation                      0x0000000184727a4c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
        73  CoreFoundation                      0x00000001847279e0 __CFRunLoopDoSource0 + 176
        74  CoreFoundation                      0x0000000184727750 __CFRunLoopDoSources0 + 244
        75  CoreFoundation                      0x0000000184726340 __CFRunLoopRun + 828
        76  CoreFoundation                      0x00000001847259ac CFRunLoopRunSpecific + 608
        77  HIToolbox                           0x000000018ecd4448 RunCurrentEventLoopInMode + 292
        78  HIT
libc++abi: terminating due to uncaught exception of type NSException
[1]    3209 abort      mnelab
cbrnr commented 7 months ago

@marsipu @larsoner do you have any idea how to fix this issue? I suspect it has to do with the Qt event loops (one for MNELAB and one for MNE-QtBrowser do not seem to work together, at least out of the box). I think it would be pretty important to get the new browser to work with MNELAB...

marsipu commented 7 months ago

Hi @cbrnr, the original error seems to come from where you try to access the canvas attribute, which the MNEQtBrowser-instance of the qt-backend doesn't have. I can test it later and upload a suggestion for a fix where the backend is considered. If block=False, there should not be a second event loop and the `MNEQtBrowserˋ-instance should be usable as any other Qt-Widget. But I'll have a look later

cbrnr commented 7 months ago

Thanks @marsipu. On macOS, execution does not even reach that line, because it crashes when the figure is being created: https://github.com/cbrnr/mnelab/blob/474e7a554412e22b4ed91dfb1181a429c8b3aeb3/mnelab/mainwindow.py#L809-L815

Adding block=True doesn't change anything either.

larsoner commented 7 months ago

@cbrnr do you have pyside6 and pyqt6 installed concurrently in your environment?

cbrnr commented 7 months ago

@larsoner no, that was my first thought as well. It is also not PySide6, because I have the same problem with @marsipu's mne-pipeline-hd using PyQt6 (see https://github.com/cbrnr/mnelab/pull/403#issuecomment-1903699069).

danieltomasz commented 6 months ago

Might be relavant https://github.com/pyqtgraph/pyqtgraph/issues/2896; https://github.com/jim-easterbrook/Photini/issues/229

This seems to be a Qt bug on MacOS Sonoma, affecting both PySide6 6.6 and PyQt6 ( through PySide6 6.5 seems to be ok) [QTBUG-120181] Crash on macOS underneath libqcocoa.dylib's _ZN20QCocoaSystemTrayIcon13emitActivatedEv - Qt Bug Tracker

danieltomasz commented 6 months ago

I can confirm that downgrading on MacOS 14.3.1 helps with crash and it gives the other expected error AttributeError: 'MNEQtBrowser' object has no attribute 'canvas'

After removing mne-qt-browser from my env dependencies and and pinning PySide6 to 6.5.3 I can plot raw file (with mnelab 0.8.6 on MacOS)

cbrnr commented 6 months ago

Nice find @danieltomasz! I'll pin PySide6 and then release a quick hotfix, ideally together with #403.

danieltomasz commented 6 months ago

installing in my env PySide6 != 6.6.1 solved crash (PySide6 6.6.2 seems to be ok again) , now "MNE QT Broswer" should be easier to fix/ use the existing PR

cbrnr commented 6 months ago

Thanks @danieltomasz! Indeed PySide6 6.6.2 does not crash anymore. However, after the browser window opens, all icons in the main MNELAB window disappear (and instead, they only show text):

Screenshot 2024-02-25 at 19 10 03

Do you also have this issue?

danieltomasz commented 6 months ago

The PR seems to fix the problem with raw_plot, but since it is using under hood mne.viz.set_browser_backend('qt'), it would be great to have similar defaults asmne.viz.plot_raw(raw), currentlymnelab` is trying to show all channels with some non-default scaling, so with long HD-EEG it make it very hard to see what shoing with eeg

With https://github.com/cbrnr/mnelab/pull/403 after raw plot data, the icons from main window are gone (edit - I just posted in the same moment - I have windows intially, but ther are gone after viewing the data)

image
cbrnr commented 6 months ago

Regarding the default settings, I think this is a separate issue which also applies to the Matplotlib backend. I'm fine with changing it to e.g. 20 channels per page and auto-scaling. Can you create a new issue?

danieltomasz commented 6 months ago

I created new issue. Regarding the icons - might it be related? https://stackoverflow.com/questions/76887079/opengl-causes-pyside6-pyqt6-application-to-reload-itself

danieltomasz commented 6 months ago

@cbrnr Quick look how the icons are set in https://github.com/cbrnr/mnelab/blob/3efff8318e65870118fbd7fdde2c9f3a4faff983/mnelab/mainwindow.py#L78 , it seems that mne-qt-browser might reset icons paths when inititializing with _qt_init_icons(), check those lines https://github.com/mne-tools/mne-qt-browser/blob/b2f9216a93e4219747044c1efdb52abf95a2c30b/mne_qt_browser/_pg_figure.py#L5162C1-L5167C22 https://github.com/mne-tools/mne-qt-browser/blob/b2f9216a93e4219747044c1efdb52abf95a2c30b/mne_qt_browser/_pg_figure.py#L3107

cbrnr commented 6 months ago

This is very helpful @danieltomasz! I think MNE Qt Browser should not overwrite existing search paths then, WDYT?

danieltomasz commented 6 months ago

Probably yes, I am not a QT specialist, something like this on mne-qt-browser side might help ‘QIcon.setThemeSearchPaths([local_icon_dir]

On Mon, 26 Feb 2024 at 07:41, Clemens Brunner @.***> wrote:

This is very helpful @danieltomasz https://github.com/danieltomasz! I think MNE Qt Browser should not overwrite existing search paths then, WDYT?

— Reply to this email directly, view it on GitHub https://github.com/cbrnr/mnelab/issues/401#issuecomment-1963419626, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB44KXLDHIB2X3PH6YQHJCTYVQVC5AVCNFSM6AAAAABB3VLCPSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNRTGQYTSNRSGY . You are receiving this because you were mentioned.Message ID: @.***>

cbrnr commented 6 months ago

Unfortunately, it's not that simple. MNELAB sets its theme search path, and when calling mne-qt-browser, it overwrites that path. Simply adding to the existing search path doesn't work, because from inside mne-qt-browser, the original search path is not accessible. I'm not sure if two Qt-based apps are meant to be running side by side like that. @marsipu or @larsoner do you have any ideas how to fix this?

cbrnr commented 6 months ago

I think at least one application (but ideally both) should include their icons as resources. Then we don't have to touch the search path at all.

larsoner commented 6 months ago

Yes I think resources is how we do it in MNE-Python and IIRC it's not too difficult

cbrnr commented 6 months ago

OK, I've now switched to including icons with the resource system (#408). However, using the current mne-qt-browser still does not work (it still removes MNELAB icons).

I tried making the same changes to mne-qt-browser, but I didn't even manage to display its own icons with resources (let alone the combination MNELAB and mne-qt-browser). For starters, the resource system is different for PySide6 and PyQt6 (the generated file contains import PySide6 when using pyside6-rcc), so we cannot easily use it unless QtPy supports it (I think it doesn't). But again, even then icons don't show up for me (except for the Help icon, which is taken from the standard theme search path apparently).

All of this mean that at least for now, MNELAB will continue to use Matplotlib as the raw browser backend. I'll probably force it just in case someone has mne-qt-browser installed.

Should I create a PR for mne-qt-browser with my attempt so that someone else can have a look?

larsoner commented 6 months ago

Did you look at how we do it in MNE-Python? We are PySide6/PyQt6 agnostic there so whatever we do with resources should in principle work. If you based your implementation on MNE-Python's then yes a WIP PR would help. If you didn't then it might not help too much since I think we should work from the existing (hopefully working?) implementation in MNE-Python

cbrnr commented 6 months ago

You mean the coreg GUI?

larsoner commented 6 months ago

Ouch looks like we actually use the path setting as well so maybe it's not worth looking at

https://github.com/mne-tools/mne-python/blob/ff1cfdd8e3ac3c05bfd5987a3e821f13cf7928f9/mne/viz/backends/_utils.py#L93

Seems like we'll need to fix it in MNE-Python, too!

At some point I think we did use resources but abandoned it, can't remember why.

In any case, yes a WIP PR would help I think

cbrnr commented 5 months ago

We've fixed most problems related to MNE-Qt-Browser. However, currently MNELAB forces the Matplotlib backend, but the plan is:

  1. Provide an option to set the desired backend ("matplotlib" or "qt") in the settings dialog.
  2. Fix crash (#403).
  3. Fix app icon issue (https://github.com/mne-tools/mne-qt-browser/issues/234).

Once these issues are fixed, users can choose between both backends (and we can close this issue).