Skip to content

Commit 5591c61

Browse files
committed
Single qt backend.
Testing all qt bindings actually caught the fact that PySide makes the backend not thread-safe.
1 parent bca86d8 commit 5591c61

29 files changed

+1366
-1355
lines changed

.github/workflows/tests.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ jobs:
177177
python -c 'import PySide2.QtCore' &&
178178
echo 'PySide2 is available' ||
179179
echo 'PySide2 is not available'
180+
python -mpip install --upgrade pyqt6 &&
181+
python -c 'import PyQt6.QtCore' &&
182+
echo 'PyQt6 is available' ||
183+
echo 'PyQt6 is not available'
184+
python -mpip install --upgrade pyside6 &&
185+
python -c 'import PySide6.QtCore' &&
186+
echo 'PySide6 is available' ||
187+
echo 'PySide6 is not available'
180188
fi
181189
python -mpip install --upgrade \
182190
-f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04 \

INSTALL.rst

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,16 @@ interface toolkits. See :ref:`what-is-a-backend` for more details on the
179179
optional Matplotlib backends and the capabilities they provide.
180180

181181
* Tk_ (>= 8.3, != 8.6.0 or 8.6.1): for the Tk-based backends.
182-
* PyQt4_ (>= 4.6) or PySide_ (>= 1.0.3) [#]_: for the Qt4-based backends.
183-
* PyQt5_ or PySide2_: for the Qt5-based backends.
182+
* PyQt6_, PySide6_, PyQt5_, or PySide2_: for the Qt-based backends.
184183
* PyGObject_: for the GTK3-based backends [#]_.
185184
* wxPython_ (>= 4) [#]_: for the wx-based backends.
186185
* pycairo_ (>= 1.11.0) or cairocffi_ (>= 0.8): for the GTK3 and/or cairo-based
187186
backends.
188187
* Tornado_: for the WebAgg backend.
189188

190189
.. _Tk: https://docs.python.org/3/library/tk.html
191-
.. _PyQt4: https://pypi.org/project/PyQt4
192-
.. _PySide: https://pypi.org/project/PySide
190+
.. _PyQt6: https://pypi.org/project/PyQt6
191+
.. _PySide6: https://pypi.org/project/PySide6
193192
.. _PyQt5: https://pypi.org/project/PyQt5
194193
.. _PySide2: https://pypi.org/project/PySide2
195194
.. _PyGObject: https://pygobject.readthedocs.io/en/latest/
@@ -198,7 +197,6 @@ optional Matplotlib backends and the capabilities they provide.
198197
.. _cairocffi: https://cairocffi.readthedocs.io/en/latest/
199198
.. _Tornado: https://pypi.org/project/tornado
200199

201-
.. [#] PySide cannot be pip-installed on Linux (but can be conda-installed).
202200
.. [#] If using pip (and not conda), PyGObject must be built from source; see
203201
https://pygobject.readthedocs.io/en/latest/devguide/dev_environ.html.
204202
.. [#] If using pip (and not conda) on Linux, wxPython wheels must be manually

doc/api/backend_qt5agg_api.rst

Lines changed: 0 additions & 10 deletions
This file was deleted.

doc/api/backend_qt5cairo_api.rst

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

2-
:mod:`matplotlib.backends.backend_qt4agg`
3-
=========================================
2+
:mod:`matplotlib.backends.backend_qtagg`
3+
========================================
44

55
**NOTE** Not included, to avoid adding a dependency to building the docs.
66

7-
.. .. automodule:: matplotlib.backends.backend_qt4agg
7+
.. .. automodule:: matplotlib.backends.backend_qtagg
88
.. :members:
99
.. :undoc-members:
1010
.. :show-inheritance:
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

2-
:mod:`matplotlib.backends.backend_qt4cairo`
2+
:mod:`matplotlib.backends.backend_qtcairo`
33
===========================================
44

55
**NOTE** Not included, to avoid adding a dependency to building the docs.
66

7-
.. .. automodule:: matplotlib.backends.backend_qt4cairo
7+
.. .. automodule:: matplotlib.backends.backend_qtcairo
88
.. :members:
99
.. :undoc-members:
1010
.. :show-inheritance:

doc/api/index_backend_api.rst

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@
1515
backend_pdf_api.rst
1616
backend_pgf_api.rst
1717
backend_ps_api.rst
18-
backend_qt4agg_api.rst
19-
backend_qt4cairo_api.rst
20-
backend_qt5agg_api.rst
21-
backend_qt5cairo_api.rst
18+
backend_qtagg_api.rst
19+
backend_qtcairo_api.rst
2220
backend_svg_api.rst
2321
backend_tkagg_api.rst
2422
backend_webagg_api.rst

doc/users/interactive.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ it also ensures that the GUI toolkit event loop is properly integrated
6363
with the command line (see :ref:`cp_integration`).
6464

6565
In this example, we create and modify a figure via an IPython prompt.
66-
The figure displays in a Qt5Agg GUI window. To configure the integration
66+
The figure displays in a QtAgg GUI window. To configure the integration
6767
and enable :ref:`interactive mode <controlling-interactive>` use the
6868
``%matplotlib`` magic:
6969

@@ -72,7 +72,7 @@ and enable :ref:`interactive mode <controlling-interactive>` use the
7272
::
7373

7474
In [1]: %matplotlib
75-
Using matplotlib backend: Qt5Agg
75+
Using matplotlib backend: QtAgg
7676

7777
In [2]: import matplotlib.pyplot as plt
7878

examples/user_interfaces/embedding_in_qt_sgskip.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,19 @@
44
===============
55
66
Simple Qt application embedding Matplotlib canvases. This program will work
7-
equally well using Qt4 and Qt5. Either version of Qt can be selected (for
8-
example) by setting the ``MPLBACKEND`` environment variable to "Qt4Agg" or
9-
"Qt5Agg", or by first importing the desired version of PyQt.
7+
equally well using any Qt binding (PyQt6, PySide6, PyQt5, PySide2). The
8+
binding can be selected by setting the ``QT_API`` environment variable to the
9+
binding name, or by first importing it.
1010
"""
1111

1212
import sys
1313
import time
1414

1515
import numpy as np
1616

17-
from matplotlib.backends.qt_compat import QtCore, QtWidgets
18-
if QtCore.qVersion() >= "5.":
19-
from matplotlib.backends.backend_qt5agg import (
20-
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
21-
else:
22-
from matplotlib.backends.backend_qt4agg import (
23-
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
17+
from matplotlib.backends.qt_compat import QtWidgets
18+
from matplotlib.backends.backend_qtagg import (
19+
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
2420
from matplotlib.figure import Figure
2521

2622

@@ -32,13 +28,15 @@ def __init__(self):
3228
layout = QtWidgets.QVBoxLayout(self._main)
3329

3430
static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
31+
# Ideally one would use self.addToolBar here, but it is slightly
32+
# incompatible between PyQt6 and other bindings, so we just add the
33+
# toolbar as a plain widget instead.
34+
layout.addWidget(NavigationToolbar(static_canvas, self))
3535
layout.addWidget(static_canvas)
36-
self.addToolBar(NavigationToolbar(static_canvas, self))
3736

3837
dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
3938
layout.addWidget(dynamic_canvas)
40-
self.addToolBar(QtCore.Qt.BottomToolBarArea,
41-
NavigationToolbar(dynamic_canvas, self))
39+
layout.addWidget(NavigationToolbar(dynamic_canvas, self))
4240

4341
self._static_ax = static_canvas.figure.subplots()
4442
t = np.linspace(0, 10, 501)
@@ -70,4 +68,4 @@ def _update_canvas(self):
7068
app.show()
7169
app.activateWindow()
7270
app.raise_()
73-
qapp.exec_()
71+
qapp.exec()

lib/matplotlib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ def use(backend, *, force=True):
10921092
10931093
- interactive backends:
10941094
GTK3Agg, GTK3Cairo, MacOSX, nbAgg,
1095-
Qt4Agg, Qt4Cairo, Qt5Agg, Qt5Cairo,
1095+
QtAgg, QtCairo, Qt4Agg, Qt4Cairo, Qt5Agg, Qt5Cairo,
10961096
TkAgg, TkCairo, WebAgg, WX, WXAgg, WXCairo
10971097
10981098
- non-interactive backends:

lib/matplotlib/backend_bases.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,14 @@ def _safe_pyplot_import():
9898
current_framework = cbook._get_running_interactive_framework()
9999
if current_framework is None:
100100
raise # No, something else went wrong, likely with the install...
101-
backend_mapping = {'qt5': 'qt5agg',
102-
'qt4': 'qt4agg',
103-
'gtk3': 'gtk3agg',
104-
'wx': 'wxagg',
105-
'tk': 'tkagg',
106-
'macosx': 'macosx',
107-
'headless': 'agg'}
101+
backend_mapping = {
102+
'qt': 'qtagg',
103+
'gtk3': 'gtk3agg',
104+
'wx': 'wxagg',
105+
'tk': 'tkagg',
106+
'macosx': 'macosx',
107+
'headless': 'agg',
108+
}
108109
backend = backend_mapping[current_framework]
109110
rcParams["backend"] = mpl.rcParamsOrig["backend"] = backend
110111
import matplotlib.pyplot as plt # Now this should succeed.
@@ -1675,7 +1676,7 @@ class FigureCanvasBase:
16751676
A high-level figure instance.
16761677
"""
16771678

1678-
# Set to one of {"qt5", "qt4", "gtk3", "wx", "tk", "macosx"} if an
1679+
# Set to one of {"qt", "gtk3", "wx", "tk", "macosx"} if an
16791680
# interactive framework is required, or None otherwise.
16801681
required_interactive_framework = None
16811682

@@ -1747,7 +1748,7 @@ def _fix_ipython_backend2gui(cls):
17471748
# don't break on our side.
17481749
return
17491750
rif = getattr(cls, "required_interactive_framework", None)
1750-
backend2gui_rif = {"qt5": "qt", "qt4": "qt", "gtk3": "gtk3",
1751+
backend2gui_rif = {"qt": "qt", "gtk3": "gtk3",
17511752
"wx": "wx", "macosx": "osx"}.get(rif)
17521753
if backend2gui_rif:
17531754
if _is_non_interactive_terminal_ipython(ip):

0 commit comments

Comments
 (0)