You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi @daliagachc, if you'd like to try a fix and verify it in your environment, it should be a matter of adding a loop_qt6 function and exit handler similar to what is done for qt5 here.
If Qt6 is installed it looks like matplotlib might be automatically trying to set qt6 up. We have test errors on napari with install --pre and matplotlib:
/tmp/.tox/py38-linux-pyside/lib/python3.8/site-packages/matplotlib/pyplot.py:2467: in <module>
install_repl_displayhook()
/tmp/.tox/py38-linux-pyside/lib/python3.8/site-packages/matplotlib/pyplot.py:138: in install_repl_displayhook
ip.enable_gui(ipython_gui_name)
/tmp/.tox/py38-linux-pyside/lib/python3.8/site-packages/ipykernel/inprocess/ipkernel.py:181: in enable_gui
enable_gui(gui, kernel=self.kernel)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
gui = 'qt6'
kernel = <ipykernel.inprocess.ipkernel.InProcessKernel object at 0x7fcb20138070>
def enable_gui(gui, kernel=None):
"""Enable integration with a given GUI"""
if gui not in loop_map:
e = "Invalid GUI request %r, valid ones are:%s" % (gui, loop_map.keys())
> raise ValueError(e)
E ValueError: Invalid GUI request 'qt6', valid ones are:dict_keys(['inline', 'nbagg', 'notebook', 'ipympl', 'widget', None, 'qt4', 'qt', 'qt5', 'wx', 'tk', 'gtk', 'gtk3', 'osx', 'asyncio'])
You need to implement an event loop for this in ipykernel/eventloops.py. If Qt6 didn't change too much with respect to version 5, it should be pretty straightforward.
hi! thanks for the input. so i did implement qt6 in a similar fashion to qt5. now gui qt6 runs from jlab for example without interrupting the kernel. however when i execute any cell in jlab the qt windows disappears
On 23. Sep 2021, at 1.56, Carlos Cordoba ***@***.***> wrote:
You need to implement an event loop for this in ipykernel/eventloops.py. If Qt6 didn't change too much with respect to version 5, it should be pretty straightforward.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
This appears to result from a weird symbiosis of Matplotlib and IPython. When you try to import pyplot within an ipykernel, Matplotlib queries IPython to get a valid Qt backend. The following code is in pyplot.py (lines 147-151):
from IPython.core.pylabtools import backend2gui
# trigger IPython's eventloop integration, if available
ipython_gui_name = backend2gui.get(get_backend())
if ipython_gui_name:
ip.enable_gui(ipython_gui_name)
If the Matplotlib use function has not been called to initialize a backend, it defaults to QtAgg, but the backend2gui dictionary in IPython 7.28 now maps that to qt6, which ipykernel does not recognize as a valid ipython_gui_name.
I can see that adding a loop_qt6 handler for PyQt6 would fix the name issue, but does that mean that it will just attempt to use PyQt6 even when it's not installed? If so, it looks as if switching QtAgg to default to PyQt6 may have been premature since it's not yet available on conda or supported by the qtpy package.
There is another more worrying aspect of the Matplotlib-IPython symbiosis. This is almost certainly a separate issue with the InProcessKernel, but it might also reflect issues with Matplotlib and IPython as well, which the people reading this might help me to identify. When you import 'pyplot', it always runs the install_repl_displayhook function that triggers the call to enable_gui that I referred to above. This then sets the kernel.eventloop to one of the loop functions defined in 'eventloops.py'. I think this is clearly a bug in the InProcessKernel, because it triggers calls to a second event loop, which the kernel is not set up for (e.g., kernel.io_loop is not defined). However, I worry about other side effects. Should a simple import do something as profound as changing event loops? Shouldn't that be the job of a specific function call like mpl.use()?
that triggers the call to enable_gui that I referred to above.
What if you simply add a return to that call if the kernel is an instance of InProcessKernel? The problem is that kernel is not very well supported because most people here focus on the two processes kernel (i.e. IPythonKernel) because it's the one that allows users to run cpu-intensive code out of our applications.
Should a simple import do something as profound as changing event loops?
Perhaps not, but I think that's the case to allow interactive plotting work out of the box as soon as you import pyplot. A lot of people is unaware of event loops and how to activate them.
@ccordoba12, I agree that is probably the reason pyplot does what it does. I think I know what to put in a PR to fix #780, which will probably resolve all these problems for me. I know that the InProcessKernel is often on life support, but it is essential to my application, which is why I monitor these discussions when I have the time.
Ah, I did not understand that IPython and ipykernel each had their own event loop code.
pyplot should be thought of as the "application" layer of Matplotlib that "just works" out of the box. We picked up the mpl -> ipython calls a while ago to remove the need for %matplotlib in the IPython shell. On the other hand mpl.use mostly just sets an rcparams and has no other impact if you have not already imported pyplot (if pyplot is imported we try to force it to change backends which may fail).
We have gone through some effort on the mpl side to avoid locking you into a given GUI framework until you create the first figure, however it seems that the install_repl_displayhook has more side effects that my 2015 comment just above that function call suggest! I would be 👍 on deferring the initial call to that function to the first time a figure gets made (I think I see how to do it....)
If the Matplotlib use function has not been called to initialize a backend, it defaults to QtAgg, but the backend2gui dictionary in IPython 7.28 now maps that to qt6, which ipykernel does not recognize as a valid ipython_gui_name.
ah, the issue here is that on the Matplotlib side Qt5 and Qt6 are similar enough that we have stuffed all of the compatibility logic back into qt_compat.py and unlike qt4 -> qt5 when we had distinct backends, we now only have QtAgg (Qt5Agg has been turned into a re-export shim for back-compatibility). In pt_inputhook/qt.py already did the same thing for Qt4 and Qt5, in ipython/ipython#13085 I did the same thing for Qt6 as well.
However, the bug I introduced was that I set up the mapping backends = { ..., 'qt6': 'QtAgg', ...} so that %matplotlib qt6 does the right (ish) thing (it will actually silently fallback to qt5....maybe that is a bug...), but when backend2gui is set up it goes back to a non-existent loop. The fix for that is to fix the reverse mapping "by hand" (like a majority of the entries at this point!).
With ipython/ipython#13179 I think the napari failures will be fixed, looking at the ipykernel event loop to see what needs to be ported from IPython...
I have a patch that get qt6 working (and solves the quickly closing windows from @daliagachc ), but there are some issues with selecting the right version of Qt which may be a bug in any of Matplotlib, IPython, or ipykernel 😞 .
hi! thanks for the input. so i did implement qt6 in a similar fashion to qt5. now gui qt6 runs from jlab for example without interrupting the kernel. however when i execute any cell in jlab the qt windows disappears
The window disappears because [even today] the way ipykernel ties in the event loop is different than IPython. In IPython, an explicit instance of QEventLoop is obtained and executed. "Quitting" it effectively pauses the event loop.
In ipykernel, it executes/quits a QApplication instance instead, and quitting that will destroy all Qt Windows.
It seems #782 is quite a ways toward the solution (including addressing this window disappearance); I was working on this today and adding support for PySide6. @tacaswell what's the status of that PR?
Dormant. I had to re-read this and remind my self that ipykernel and ipython have their own event loop integrations .... 🤦🏻
@shaperilio Please feel free to take over that PR (or drop my commit and start from scratch). I would recommend using IPython as a reference implementation either way.
I am closing this as it was fixed by #1054 and I've confirmed it works as expected after the recent changes to backend resolution in IPython and Matplotlib.
Activity
blink1073 commentedon Sep 21, 2021
Hi @daliagachc, if you'd like to try a fix and verify it in your environment, it should be a matter of adding a
loop_qt6function and exit handler similar to what is done for qt5 here.Carreau commentedon Sep 22, 2021
+1, there was ipython/ipython#13085 on the IPython side.
If Qt6 is installed it looks like matplotlib might be automatically trying to set qt6 up. We have test errors on napari with install --pre and matplotlib:
@tacaswell FYI.
ccordoba12 commentedon Sep 22, 2021
You need to implement an event loop for this in
ipykernel/eventloops.py. If Qt6 didn't change too much with respect to version 5, it should be pretty straightforward.daliagachc commentedon Sep 23, 2021
rayosborn commentedon Oct 2, 2021
This appears to result from a weird symbiosis of Matplotlib and IPython. When you try to import pyplot within an ipykernel, Matplotlib queries IPython to get a valid Qt backend. The following code is in pyplot.py (lines 147-151):
If the Matplotlib use function has not been called to initialize a backend, it defaults to
QtAgg, but thebackend2guidictionary in IPython 7.28 now maps that toqt6, which ipykernel does not recognize as a validipython_gui_name.I can see that adding a
loop_qt6handler for PyQt6 would fix the name issue, but does that mean that it will just attempt to use PyQt6 even when it's not installed? If so, it looks as if switchingQtAggto default to PyQt6 may have been premature since it's not yet available on conda or supported by the qtpy package.ccordoba12 commentedon Oct 2, 2021
I also think that's not the right approach, at least until Qt6 has more widespread usage.
@Carreau, would you accept a patch to revert it?
Carreau commentedon Oct 3, 2021
Yes, that would be ok.
tacaswell commentedon Oct 4, 2021
I will try to look at this tomorrow.
rayosborn commentedon Oct 6, 2021
There is another more worrying aspect of the Matplotlib-IPython symbiosis. This is almost certainly a separate issue with the InProcessKernel, but it might also reflect issues with Matplotlib and IPython as well, which the people reading this might help me to identify. When you import 'pyplot', it always runs the
install_repl_displayhookfunction that triggers the call toenable_guithat I referred to above. This then sets thekernel.eventloopto one of theloopfunctions defined in 'eventloops.py'. I think this is clearly a bug in the InProcessKernel, because it triggers calls to a second event loop, which the kernel is not set up for (e.g.,kernel.io_loopis not defined). However, I worry about other side effects. Should a simple import do something as profound as changing event loops? Shouldn't that be the job of a specific function call likempl.use()?ccordoba12 commentedon Oct 6, 2021
What if you simply add a
returnto that call if the kernel is an instance ofInProcessKernel? The problem is that kernel is not very well supported because most people here focus on the two processes kernel (i.e.IPythonKernel) because it's the one that allows users to run cpu-intensive code out of our applications.Perhaps not, but I think that's the case to allow interactive plotting work out of the box as soon as you import
pyplot. A lot of people is unaware of event loops and how to activate them.rayosborn commentedon Oct 6, 2021
@ccordoba12, I agree that is probably the reason pyplot does what it does. I think I know what to put in a PR to fix #780, which will probably resolve all these problems for me. I know that the InProcessKernel is often on life support, but it is essential to my application, which is why I monitor these discussions when I have the time.
ccordoba12 commentedon Oct 6, 2021
Please push it and I'll be happy to review it.
tacaswell commentedon Oct 7, 2021
Ah, I did not understand that IPython and ipykernel each had their own event loop code.
pyplotshould be thought of as the "application" layer of Matplotlib that "just works" out of the box. We picked up the mpl -> ipython calls a while ago to remove the need for%matplotlibin the IPython shell. On the other handmpl.usemostly just sets an rcparams and has no other impact if you have not already imported pyplot (if pyplot is imported we try to force it to change backends which may fail).We have gone through some effort on the mpl side to avoid locking you into a given GUI framework until you create the first figure, however it seems that the
install_repl_displayhookhas more side effects that my 2015 comment just above that function call suggest! I would be 👍 on deferring the initial call to that function to the first time a figure gets made (I think I see how to do it....)ah, the issue here is that on the Matplotlib side Qt5 and Qt6 are similar enough that we have stuffed all of the compatibility logic back into
qt_compat.pyand unlike qt4 -> qt5 when we had distinct backends, we now only have QtAgg (Qt5Agg has been turned into a re-export shim for back-compatibility). Inpt_inputhook/qt.pyalready did the same thing for Qt4 and Qt5, in ipython/ipython#13085 I did the same thing for Qt6 as well.However, the bug I introduced was that I set up the mapping
backends = { ..., 'qt6': 'QtAgg', ...}so that%matplotlib qt6does the right (ish) thing (it will actually silently fallback to qt5....maybe that is a bug...), but whenbackend2guiis set up it goes back to a non-existent loop. The fix for that is to fix the reverse mapping "by hand" (like a majority of the entries at this point!).With ipython/ipython#13179 I think the napari failures will be fixed, looking at the ipykernel event loop to see what needs to be ported from IPython...
tacaswell commentedon Oct 7, 2021
I have a patch that get qt6 working (and solves the quickly closing windows from @daliagachc ), but there are some issues with selecting the right version of Qt which may be a bug in any of Matplotlib, IPython, or ipykernel 😞 .
shaperilio commentedon Dec 8, 2022
The window disappears because [even today] the way
ipykernelties in the event loop is different thanIPython. InIPython, an explicit instance ofQEventLoopis obtained and executed. "Quitting" it effectively pauses the event loop.In
ipykernel, it executes/quits aQApplicationinstance instead, and quitting that will destroy all Qt Windows.It seems #782 is quite a ways toward the solution (including addressing this window disappearance); I was working on this today and adding support for
PySide6. @tacaswell what's the status of that PR?tacaswell commentedon Dec 8, 2022
Dormant. I had to re-read this and remind my self that ipykernel and ipython have their own event loop integrations .... 🤦🏻
@shaperilio Please feel free to take over that PR (or drop my commit and start from scratch). I would recommend using IPython as a reference implementation either way.
shaperilio commentedon Dec 8, 2022
Will do; thanks @tacaswell - you definitely made some changes I'll adopt.
ianthomas23 commentedon May 14, 2024
I am closing this as it was fixed by #1054 and I've confirmed it works as expected after the recent changes to backend resolution in IPython and Matplotlib.