Skip to content

[Bug]: VSCode matplotlib interactive mode cannot import Qt bindings #25673

Closed

Description

@kwsp

Bug summary

Running in VS Code interactive mode, %matplotlib qt throws an exception ImportError: Failed to import any of the following Qt binding modules: PyQt6, PySide6, PyQt5, PySide2. However, PySide6 is installed.

Error trace
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
[c:\Users\nhl08\code\oct-invivo-analysis\flatten.py](file:///C:/Users/nhl08/code/oct-invivo-analysis/flatten.py) in line 12
      [13](file:///c%3A/Users/nhl08/code/oct-invivo-analysis/flatten.py?line=12) import matplotlib.pyplot as plt
     [15](file:///c%3A/Users/nhl08/code/oct-invivo-analysis/flatten.py?line=14) from oct_utils import imshow, imshow2
---> [17](file:///c%3A/Users/nhl08/code/oct-invivo-analysis/flatten.py?line=16) get_ipython().run_line_magic('matplotlib', 'qt')

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\IPython\core\interactiveshell.py:2414](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py:2414), in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
   [2412](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2411)     kwargs['local_ns'] = self.get_local_scope(stack_depth)
   [2413](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2412) with self.builtin_trap:
-> [2414](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2413)     result = fn(*args, **kwargs)
   [2416](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2415) # The code below prevents the output from being displayed
   [2417](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2416) # when using magics with decodator @output_can_be_silenced
   [2418](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2417) # when the last Python token in the expression is a ';'.
   [2419](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=2418) if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\IPython\core\magics\pylab.py:99](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/magics/pylab.py:99), in PylabMagics.matplotlib(self, line)
     [97](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/magics/pylab.py?line=96)     print("Available matplotlib backends: %s" % backends_list)
     [98](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/magics/pylab.py?line=97) else:
---> [99](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/magics/pylab.py?line=98)     gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui)
    [100](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/magics/pylab.py?line=99)     self._show_matplotlib_backend(args.gui, backend)

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\IPython\core\interactiveshell.py:3600](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py:3600), in InteractiveShell.enable_matplotlib(self, gui)
   [3596](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3595)         print('Warning: Cannot change to a different GUI toolkit: %s.'
   [3597](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3596)                 ' Using %s instead.' % (gui, self.pylab_gui_select))
   [3598](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3597)         gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
-> [3600](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3599) pt.activate_matplotlib(backend)
   [3601](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3600) configure_inline_support(self, backend)
   [3603](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3602) # Now we must activate the gui pylab wants to use, and fix %run to take
   [3604](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/interactiveshell.py?line=3603) # plot updates into account

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\IPython\core\pylabtools.py:360](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py:360), in activate_matplotlib(backend)
    [355](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=354) # Due to circular imports, pyplot may be only partially initialised
    [356](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=355) # when this function runs.
    [357](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=356) # So avoid needing matplotlib attribute-lookup to access pyplot.
    [358](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=357) from matplotlib import pyplot as plt
--> [360](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=359) plt.switch_backend(backend)
    [362](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=361) plt.show._needmain = False
    [363](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=362) # We need to detect at runtime whether show() is called by the user.
    [364](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/IPython/core/pylabtools.py?line=363) # For this, we wrap it into a decorator which adds a 'called' flag.

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\matplotlib\pyplot.py:271](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py:271), in switch_backend(newbackend)
    [268](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=267) # have to escape the switch on access logic
    [269](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=268) old_backend = dict.__getitem__(rcParams, 'backend')
--> [271](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=270) backend_mod = importlib.import_module(
    [272](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=271)     cbook._backend_module_name(newbackend))
    [274](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=273) required_framework = _get_required_interactive_framework(backend_mod)
    [275](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/pyplot.py?line=274) if required_framework is not None:

File [c:\Users\nhl08\miniconda3\envs\sim\lib\importlib\__init__.py:126](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/importlib/__init__.py:126), in import_module(name, package)
    [124](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/importlib/__init__.py?line=123)             break
    [125](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/importlib/__init__.py?line=124)         level += 1
--> [126](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/importlib/__init__.py?line=125) return _bootstrap._gcd_import(name[level:], package, level)

File :1050, in _gcd_import(name, package, level)

File :1027, in _find_and_load(name, import_)

File :1006, in _find_and_load_unlocked(name, import_)

File :688, in _load_unlocked(spec)

File :883, in exec_module(self, module)

File :241, in _call_with_frames_removed(f, *args, **kwds)

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\matplotlib\backends\backend_qt5agg.py:7](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py:7)
      [4](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=3) from .. import backends
      [6](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=5) backends._QT_FORCE_QT5_BINDING = True
----> [7](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=6) from .backend_qtagg import (    # noqa: F401, E402 # pylint: disable=W0611
      [8](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=7)     _BackendQTAgg, FigureCanvasQTAgg, FigureManagerQT, NavigationToolbar2QT,
      [9](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=8)     FigureCanvasAgg, FigureCanvasQT)
     [12](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=11) @_BackendQTAgg.export
     [13](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=12) class _BackendQT5Agg(_BackendQTAgg):
     [14](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qt5agg.py?line=13)     pass

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\matplotlib\backends\backend_qtagg.py:9](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py:9)
      [5](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py?line=4) import ctypes
      [7](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py?line=6) from matplotlib.transforms import Bbox
----> [9](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py?line=8) from .qt_compat import QT_API, _enum
     [10](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py?line=9) from .backend_agg import FigureCanvasAgg
     [11](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/backend_qtagg.py?line=10) from .backend_qt import QtCore, QtGui, _BackendQT, FigureCanvasQT

File [c:\Users\nhl08\miniconda3\envs\sim\lib\site-packages\matplotlib\backends\qt_compat.py:135](file:///C:/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py:135)
    [133](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=132)         break
    [134](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=133)     else:
--> [135](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=134)         raise ImportError(
    [136](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=135)             "Failed to import any of the following Qt binding modules: {}"
    [137](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=136)             .format(", ".join(_ETS.values())))
    [138](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=137) else:  # We should not get there.
    [139](file:///c%3A/Users/nhl08/miniconda3/envs/sim/lib/site-packages/matplotlib/backends/qt_compat.py?line=138)     raise AssertionError(f"Unexpected QT_API: {QT_API}")

ImportError: Failed to import any of the following Qt binding modules: PyQt6, PySide6, PyQt5, PySide2

Code for reproduction

Run in a VS Code interactive cell

# %%
import matplotlib.pyplot as plt

%matplotlib qt

Additional information

ipykernel: 6.22.0
ipython: 8.12.0
ipywidgets: 8.0.6

Operating system

Windows 10 and Windows 11 (2 separate computers)

Matplotlib Version

3.7.1

Matplotlib Backend

Qt5Agg

Python version

3.10.10

Jupyter version

No response

Installation

pip

Activity

  1. tacaswell commented on Apr 13, 2023

    @tacaswell
    Member

    Are you sure that pyside6 is installed in the environment that is being used for the terminal.

  2. kwsp commented on Apr 13, 2023

    @kwsp
    ContributorAuthor

    Yes. In the same interactive shell, I can run the following cell

    # %%
    import PySide6
    print(PySide6.__version__)  # Prints 6.5.0
  3. kwsp commented on Apr 13, 2023

    @kwsp
    ContributorAuthor

    When I start python from the command line and try to plot things, interactive plots work. It's only in VS Code interactive mode, when I try to enable interactive plots with %matplotlib qt does this happen.

  4. tacaswell commented on Apr 13, 2023

    @tacaswell
    Member

    If you import pyside6 before you do %matplotlib qt does it work?

  5. kwsp commented on Apr 13, 2023

    @kwsp
    ContributorAuthor

    It does not unfortunately. Just tested in a fresh shell:

    # %%
    import PySide6
    import matplotlib.pyplot as plt
    
    %matplotlib qt
    ImportError: Failed to import any of the following Qt binding modules: PyQt6, PySide6, PyQt5, PySide2
    

    I also want to add that this has been happening to me for many months, on two separate machines (Windows 10 and Windows 11).

  6. tacaswell commented on Apr 13, 2023

    @tacaswell
    Member

    Can you try the code in

    elif QT_API == QT_API_PYSIDE6:
    from PySide6 import QtCore, QtGui, QtWidgets, __version__
    import shiboken6
    def _isdeleted(obj): return not shiboken6.isValid(obj)
    if parse_version(__version__) >= parse_version('6.4'):
    _to_int = operator.attrgetter('value')
    else:
    _to_int = int
    to verify that works as expected?

    does %gui qt work?

    Does

    import PySide6
    import matplotlib.pyplot as plt
    plt.ion()
    fig, ax = plt.subplots()
    

    work?

    What version of pyside6?

    In the shells where it works can you check

    fig = plt.gcf() # or get a Figure object however you want
    print(type(fig.canvas).mro()
    

    to make sure it really is using pyside6 in those cases.

    Sorry for asking many questions, I do not have a window system set up to reproduce this.

  7. kwsp commented on Apr 13, 2023

    @kwsp
    ContributorAuthor

    Can you try the code in

    elif QT_API == QT_API_PYSIDE6:
    from PySide6 import QtCore, QtGui, QtWidgets, __version__
    import shiboken6
    def _isdeleted(obj): return not shiboken6.isValid(obj)
    if parse_version(__version__) >= parse_version('6.4'):
    _to_int = operator.attrgetter('value')
    else:
    _to_int = int

    to verify that works as expected?

    This works if I run directly in the shell.

    does %gui qt work?

    This line runs without exception, but matplotlib would still use the Agg backend.

    Does

    import PySide6
    import matplotlib.pyplot as plt
    plt.ion()
    fig, ax = plt.subplots()
    

    work?

    This executes without exception, but the result plot is still inline.

    What version of pyside6?

    6.5.0

    In the shells where it works can you check

    fig = plt.gcf() # or get a Figure object however you want
    print(type(fig.canvas).mro()
    

    to make sure it really is using pyside6 in those cases.

    It's not using the PySide6 backend: [<class 'matplotlib.backends.backend_agg.FigureCanvasAgg'>, <class 'matplotlib.backend_bases.FigureCanvasBase'>, <class 'object'>]

    Sorry for asking many questions, I do not have a window system set up to reproduce this.

    No I understand. Thanks for your help. I'm an absolute noob with Windows but I need to develop native Windows apps for work :(

  8. tacaswell commented on Apr 14, 2023

    @tacaswell
    Member

    Can you get a Pyside6 "hello world" app to work in the vscode terminal?

    Another thing I just noticed is that there is "conda" in your paths, but you said you installed via pip.

    Try making a fresh environment and installing everything from conda. Mixing conda and wheels can go bad in odd ways (see https://pypackaging-native.github.io).

    Can you try older versions of pyside?

    If you use

    plt.switch('qtagg')
    

    early does that make any difference?

  9. kwsp commented on Apr 24, 2023

    @kwsp
    ContributorAuthor

    plt.switch_backend('qtagg') gave the same error: ImportError: Failed to import any of the following Qt binding modules: PyQt6, PySide6, PyQt5, PySide2

    In the same VS Code interactive shell, I can run the following hello world program with PySide6 and a Qt window pops up.

    from PySide6 import QtWidgets
    
    app = QtWidgets.QApplication()
    win = QtWidgets.QWidget()
    win.show()
    app.exec()

    This actually isn't specific to Windows and the above results are from an Ubuntu 22.04 machine.

  10. kwsp commented on Apr 24, 2023

    @kwsp
    ContributorAuthor

    The reason I'm using conda + pip:

    1. Conda is great at managing virtual environments. pip doesn't do that.
    2. My packages are all declared with a pyproject.toml file. I can then easily install my packages with pip install . and have pip manage the dependencies for me. I have yet to find a painless way to manage my own packages with conda.

    That said, in this case, I'm exclusively using pip to manage packages in this environment and only using conda as the python version/virtual environment manager, which I heard is innocuous.

    Re: mixing conda env and pip - I just took a look, even matplotlib (when using conda virtual environments) needs to use pip install -e . to install matplotlib...: https://matplotlib.org/devdocs/devel/development_setup.html#create-a-dedicated-environment

  11. tacaswell commented on Apr 24, 2023

    @tacaswell
    Member

    I can not reproduce this (I got the interactive window by right click -> "run in interactive window" on an empty file and selected the system Python (which on my system has enough of the stack installed) for the Python that vscode is using).

    Looking at the code in qt_compat.py can you sort out exactly what is failing when we try each of the bindings?

  12. kwsp commented on Apr 25, 2023

    @kwsp
    ContributorAuthor

    I looked into qt_compat.py, and when I execute

    import matplotlib.backends.qt_compat
    matplotlib.backends.qt_compat._setup_pyqt5plus()

    I get the same exception.

    However, I just found a fix! Since I know I'm using PySide6, I can run this line

    from PySide6 import QtCore, QtGui, QtWidgets, __version__
    no problem, since PySide6 has always been installed. Once I do that, the above imports of qt_compat._setup_pyqt5plus() works and %matplotlib qt works.

    from PySide6 import QtCore, QtGui, QtWidgets, __version__
    import shiboken6
  13. kwsp commented on Apr 25, 2023

    @kwsp
    ContributorAuthor

    Ok I stepped through qt_compat.py with a debugger and found the issue.

    When I run %matplotlib qt, mpl loads qt_compat.py which in turn executes the file.

    if sys.modules.get("PyQt6.QtCore"):
    QT_API = QT_API_PYQT6
    elif sys.modules.get("PySide6.QtCore"):
    QT_API = QT_API_PYSIDE6
    elif sys.modules.get("PyQt5.QtCore"):
    QT_API = QT_API_PYQT5
    elif sys.modules.get("PySide2.QtCore"):
    QT_API = QT_API_PYSIDE2

    After this, QT_API remains undefined because no Qt bindings have been imported yet. So, we fall through to this case:

    # Otherwise, check the QT_API environment variable (from Enthought). This can
    # only override the binding, not the backend (in other words, we check that the
    # requested backend actually matches). Use _get_backend_or_none to avoid
    # triggering backend resolution (which can result in a partially but
    # incompletely imported backend_qt5).
    elif (mpl.rcParams._get_backend_or_none() or "").lower().startswith("qt5"):
    if QT_API_ENV in ["pyqt5", "pyside2"]:
    QT_API = _ETS[QT_API_ENV]
    else:
    _QT_FORCE_QT5_BINDING = True # noqa
    QT_API = None
    # A non-Qt backend was selected but we still got there (possible, e.g., when
    # fully manually embedding Matplotlib in a Qt app without using pyplot).

    For my environment, mpl.rcParams._get_backend_or_none() returns Qt5Agg, even though I have no Qt5 bindings installed. Still, we run into this case

    _QT_FORCE_QT5_BINDING = True # noqa

    So now, QT_API = None and _QT_FORCE_QT5_BINDING = True, and we fall though to this case while _setup_qt5plus() is never executed.

    if _QT_FORCE_QT5_BINDING:

    Obviously, we now get to this line since no Qt5 bindings are installed.

    My work around of importing PySide6.QtCore manually above basically negates this issue because once Qt6 bindings are in sys.modules, qt_compat.py would set QT_API = QT_API_PYSIDE6.

  14. kwsp commented on Apr 25, 2023

    @kwsp
    ContributorAuthor

    On a first pass look, it seems for me this is caused by

    _QT_FORCE_QT5_BINDING = True # noqa

    which if I check git blame, you committed 2bc0c1c

    So the question is: is this line of forcing Qt5 causing this bug, or is it the fact that MPL is using Qt5Agg in my environment when I only have Qt6 bindings installed the problem? Am not familiar with Agg backends and what they mean so would love your input

  15. tacaswell commented on Apr 25, 2023

    @tacaswell
    Member

    For my environment, mpl.rcParams._get_backend_or_none() returns Qt5Agg, even though I have no Qt5 bindings installed.

    This says something in your system is setting the backend to 'qt5agg' which we take to mean "I want to us Qt5" (see #22005 and the linked issuse). Is there something in your environment forcing the backend to 'qt5agg'? Could be an matplotlibrc or a mpl.use in a start up script.

    The bug to fix here is that if we are restricting to Qt5 then the error message should not list the Qt6 bindings!

  16. kwsp commented on Apr 25, 2023

    @kwsp
    ContributorAuthor

    I doubt its an environment issue, since I can reproduce this problem on 3 separate machines (Windows 10, Windows 11, Ubuntu 22.04) with a clean conda environment. Could you point me to how mpl selects the default backend? I'm curious to see where in code MPL decides to use the Qt5Agg backend by default. I just tested again in a clean conda environment on Windows 10, with just matplotlib and PySide6 installed, and trying %matplotlib qt still gives me that exception. Here's my pip list

    (test) PS C:\Users\tnie\code\tmp> pip list
    Package                       Version
    ----------------------------- -------
    asttokens                     2.2.1
    backcall                      0.2.0
    backports.functools-lru-cache 1.6.4
    colorama                      0.4.6
    contourpy                     1.0.7
    cycler                        0.11.0
    debugpy                       1.5.1
    decorator                     5.1.1
    executing                     1.2.0
    fonttools                     4.39.3
    importlib-metadata            6.6.0
    ipykernel                     6.15.0
    ipython                       8.12.0
    jedi                          0.18.2
    jupyter_client                8.2.0
    jupyter_core                  5.3.0
    kiwisolver                    1.4.4
    matplotlib                    3.7.1
    matplotlib-inline             0.1.6
    nest-asyncio                  1.5.6
    numpy                         1.24.3
    packaging                     23.1
    parso                         0.8.3
    pickleshare                   0.7.5
    Pillow                        9.5.0
    pip                           23.0.1
    platformdirs                  3.3.0
    prompt-toolkit                3.0.38
    psutil                        5.9.0
    pure-eval                     0.2.2
    Pygments                      2.15.1
    pyparsing                     3.0.9
    PySide6                       6.5.0
    PySide6-Addons                6.5.0
    PySide6-Essentials            6.5.0
    python-dateutil               2.8.2
    pywin32                       305.1
    pyzmq                         23.2.0
    setuptools                    66.0.0
    shiboken6                     6.5.0
    six                           1.16.0
    stack-data                    0.6.2
    tornado                       6.2
    traitlets                     5.9.0
    typing_extensions             4.5.0
    wcwidth                       0.2.6
    wheel                         0.38.4
    zipp                          3.15.0
    
  17. tacaswell commented on Apr 25, 2023

    @tacaswell
    Member

    I'm curious to see where in code MPL decides to use the Qt5Agg backend by default.

    It should not,

    if newbackend is rcsetup._auto_backend_sentinel:
    current_framework = cbook._get_running_interactive_framework()
    mapping = {'qt': 'qtagg',
    'gtk3': 'gtk3agg',
    'gtk4': 'gtk4agg',
    'wx': 'wxagg',
    'tk': 'tkagg',
    'macosx': 'macosx',
    'headless': 'agg'}
    best_guess = mapping.get(current_framework, None)
    if best_guess is not None:
    candidates = [best_guess]
    else:
    candidates = []
    candidates += [
    "macosx", "qtagg", "gtk4agg", "gtk3agg", "tkagg", "wxagg"]
    # Don't try to fallback on the cairo-based backends as they each have
    # an additional dependency (pycairo) over the agg-based backend, and
    # are of worse quality.
    for candidate in candidates:
    try:
    switch_backend(candidate)
    except ImportError:
    continue
    else:
    rcParamsOrig['backend'] = candidate
    return
    else:
    # Switching to Agg should always succeed; if it doesn't, let the
    # exception propagate out.
    switch_backend("agg")
    rcParamsOrig["backend"] = "agg"
    return
    is our fallback logic which is why I think it is something else setting the backend to 'qt5agg'.

  18. kwsp commented on Apr 26, 2023

    @kwsp
    ContributorAuthor

    Here's are the exact steps to reproduce on Windows 10 and Windows 11.

    1. Create a clean Conda environment and install deps

    conda create -y -n test python=3.10
    conda activate test
    # make sure env is actually active and make sure pip comes from this env.
    pip install matplotlib ipykernel PySide6  # all packages are pip installed.
    

    2. In VS Code interactive, run the following cells step by step

    # %%
    import matplotlib.pyplot as plt
    import matplotlib as mpl
    
    # %%
    mpl.get_backend()  # returns 'module://matplotlib_inline.backend_inline'
    
    # %%
    plt.plot(range(10))  # Plots inline OK
    
    # %%
    mpl.get_backend()  # Still returns 'module://matplotlib_inline.backend_inline'
    
    # %%
    %matplotlib qt
    plt.plot(range(10))  # ImportError: Failed to import any of the following Qt binding modules...
    
    # %%
    mpl.get_backend()  # returns 'Qt5Agg'
  19. kwsp commented on Apr 26, 2023

    @kwsp
    ContributorAuthor

    I'm curious to see where in code MPL decides to use the Qt5Agg backend by default.

    It should not,

    if newbackend is rcsetup._auto_backend_sentinel:
    current_framework = cbook._get_running_interactive_framework()
    mapping = {'qt': 'qtagg',
    'gtk3': 'gtk3agg',
    'gtk4': 'gtk4agg',
    'wx': 'wxagg',
    'tk': 'tkagg',
    'macosx': 'macosx',
    'headless': 'agg'}
    best_guess = mapping.get(current_framework, None)
    if best_guess is not None:
    candidates = [best_guess]
    else:
    candidates = []
    candidates += [
    "macosx", "qtagg", "gtk4agg", "gtk3agg", "tkagg", "wxagg"]
    # Don't try to fallback on the cairo-based backends as they each have
    # an additional dependency (pycairo) over the agg-based backend, and
    # are of worse quality.
    for candidate in candidates:
    try:
    switch_backend(candidate)
    except ImportError:
    continue
    else:
    rcParamsOrig['backend'] = candidate
    return
    else:
    # Switching to Agg should always succeed; if it doesn't, let the
    # exception propagate out.
    switch_backend("agg")
    rcParamsOrig["backend"] = "agg"
    return

    is our fallback logic which is why I think it is something else setting the backend to 'qt5agg'.

    I set a breakpoint on line 234 here, stepped through the code that raised the ImportError, and confirmed this branch was never hit.

  20. kwsp commented on Apr 26, 2023

    @kwsp
    ContributorAuthor

    Ok what the hell. The problem isn't with matplotlib, but IPython. I hardcore stepped through the code this time, and it turns out if you do %matplotlib qt, qt always maps to Qt5Agg. So if I only have Qt6 bindings, this would always break because IPython tells matplotlibto use Qt5Agg first, before matplotlib tries to actually import bindings.

    https://github.com/ipython/ipython/blob/main/IPython/core/pylabtools.py#L26

    https://github.com/ipython/ipython/blob/main/IPython/core/pylabtools.py#L301-L322

  21. ksunden commented on Apr 26, 2023

    @ksunden
    Member

    (I was about to post the same link, in fact just for posterity, I'll post the permalink rather than the main branch which can change: https://github.com/ipython/ipython/blob/396593e7ad8cab3a9c36fb0f3e26cbf79cff069c/IPython/core/pylabtools.py#L26)

    Short term, you should be resolved by doing %matplotlib qt6 instead... longer term, perhaps IPython should update that mapping.

    Regardless, going to close as this is not a change we can do, as far as I can tell

  22. ksunden commented on Apr 26, 2023

    @ksunden
    Member

    Thought a little bit more and opened #25772, which would at least have helped narrow in on this, by not purporting to have tried qt6 when it does not actually do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions