I can make a Matplotlib figure take up the entire window by replacing the central widget, but that means I can't add any other UI controls. Is there a way to embed a Matplotlib plot inside a Qt layout alongside buttons, labels, and other widgets — and can I use Qt Designer to do it?
Great question, and the answer is yes! The Matplotlib canvas (FigureCanvasQTAgg) is a regular QWidget. That means you can place it inside any layout, next to any other widgets, just like you would with a QPushButton or a QLabel. You're not limited to giving it the entire window.
Let's walk through how to do this, starting with a pure-code approach and then covering how to integrate with Qt Designer.
Matplotlib's Canvas is Just a QWidget
When you create a Matplotlib canvas for use in a PyQt6 application, you use FigureCanvasQTAgg from matplotlib.backends.backend_qt5agg. Despite the "qt5" in the module path, this backend works with PyQt6 as well.
Because FigureCanvasQTAgg inherits from QWidget, you can:
- Add it to any
QVBoxLayout,QHBoxLayout, orQGridLayout - Place it inside a
QFrame,QGroupBox, or any other container - Combine it freely with buttons, sliders, labels, and other controls
Embedding a Plot in a Layout with Other Widgets
Here's a complete example that places a Matplotlib plot alongside a button and a label, all inside a vertical layout. If you're new to layouts in PyQt6, they allow you to arrange widgets automatically within a window.
import sys
import matplotlib
matplotlib.use("QtAgg")
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QVBoxLayout,
QWidget, QPushButton, QLabel,
)
class MplCanvas(FigureCanvasQTAgg):
"""A Matplotlib canvas that acts as a PyQt6 widget."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super().__init__(fig)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Matplotlib in a Layout")
# Create the Matplotlib canvas widget.
self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
self.canvas.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
# Create some other widgets.
label = QLabel("This is a label above the plot")
button = QPushButton("Click me")
button.clicked.connect(self.on_button_clicked)
# Arrange everything in a vertical layout.
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(self.canvas)
layout.addWidget(button)
# A QMainWindow needs a central widget to hold the layout.
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def on_button_clicked(self):
self.canvas.axes.cla() # Clear the axes.
self.canvas.axes.plot([0, 1, 2, 3, 4], [40, 3, 20, 1, 10])
self.canvas.draw() # Refresh the canvas.
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Run this and you'll see a window with a label at the top, a Matplotlib plot in the middle, and a button at the bottom. Clicking the button redraws the plot with different data. The canvas behaves exactly like any other widget in the layout.
Using Qt Designer
If you prefer building your UI visually in Qt Designer, you have two good options for including a Matplotlib plot.
Option 1: Promote a QWidget to a Matplotlib Canvas
Qt Designer doesn't know about FigureCanvasQTAgg out of the box, but it has a feature called widget promotion that lets you place a placeholder QWidget and tell Qt to swap it for your custom class at runtime.
Here's how:
-
In Qt Designer, drag a plain QWidget onto your form and position it where you want the plot to appear. Give it an object name like
matplotlib_widget. -
Right-click the widget and choose Promote to...
-
Fill in the promotion dialog:
- Promoted class name:
MplCanvas -
Header file:
mplcanvas(this is the Python module name, without.py) -
Click Add, then Promote.
-
Save your
.uifile.
Now you need a Python file called mplcanvas.py that contains the MplCanvas class:
# mplcanvas.py
import matplotlib
matplotlib.use("QtAgg")
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super().__init__(fig)
When you load the .ui file in your application (using uic.loadUi or by compiling it with pyuic6), Qt will create an instance of MplCanvas wherever you placed the promoted widget. You can then access it by its object name and draw on it:
import sys
from PyQt6 import uic
from PyQt6.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("mainwindow.ui", self)
# Access the promoted widget by its object name.
self.matplotlib_widget.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
self.matplotlib_widget.draw()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
This approach gives you full visual control over the layout in Qt Designer while still embedding a real Matplotlib plot. The same widget promotion technique is used to embed custom widgets like PyQtGraph plots in Designer-built UIs.
Option 2: Build the Layout in Designer, Add the Plot in Code
If widget promotion feels like too much setup, there's a simpler alternative. Design your UI in Qt Designer with a placeholder QWidget (or a QVBoxLayout inside a container), and then add the Matplotlib canvas to that placeholder from your Python code.
For example, if you've placed a QWidget named plot_container in your Designer layout:
import sys
import matplotlib
matplotlib.use("QtAgg")
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from PyQt6 import uic
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QVBoxLayout,
)
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super().__init__(fig)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("mainwindow.ui", self)
# Create the canvas and add it into the placeholder widget.
self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
layout = QVBoxLayout()
layout.addWidget(self.canvas)
self.plot_container.setLayout(layout)
# Now plot something.
self.canvas.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
self.canvas.draw()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
This way, you design all the surrounding UI (buttons, menus, labels, status bars) in Qt Designer, and just inject the plot widget from code. Using Qt Designer and writing layout code by hand are not mutually exclusive — you can mix and match freely.
Adding a Navigation Toolbar
Matplotlib provides a navigation toolbar (NavigationToolbar2QT) that gives users zoom, pan, and save controls. Since the toolbar is also a QWidget, you can add it to your layout right alongside the canvas:
import sys
import matplotlib
matplotlib.use("QtAgg")
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg, NavigationToolbar2QT
from matplotlib.figure import Figure
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QVBoxLayout,
QWidget, QPushButton,
)
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super().__init__(fig)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Matplotlib with Toolbar")
self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
self.canvas.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
toolbar = NavigationToolbar2QT(self.canvas, self)
button = QPushButton("Update Plot")
button.clicked.connect(self.update_plot)
layout = QVBoxLayout()
layout.addWidget(toolbar)
layout.addWidget(self.canvas)
layout.addWidget(button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def update_plot(self):
self.canvas.axes.cla()
self.canvas.axes.plot([0, 1, 2, 3, 4], [40, 3, 20, 1, 10])
self.canvas.draw()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
This gives you a complete application with a toolbar for interacting with the plot, the plot itself, and a custom button — all in one window.
Summary
The Matplotlib FigureCanvasQTAgg is a standard QWidget, so you can embed it in any layout alongside other widgets. You have full flexibility:
- Pure code: Create layouts and add the canvas widget directly.
- Qt Designer with promotion: Place a
QWidgetin Designer, promote it to your canvas class, and it will be created automatically when the UI loads. - Qt Designer with code injection: Design most of the UI in Designer, then add the canvas to a placeholder widget from your Python code.
All three approaches work well. Choose whichever fits your workflow — or combine them as needed. For a more in-depth look at plotting with Matplotlib in PyQt6, including animated and interactive plots, see our complete Matplotlib with PyQt6 tutorial. If you're looking for a high-performance alternative for real-time or scientific data visualization, you might also want to explore plotting with PyQtGraph in PyQt6.
Packaging Python Applications with PyInstaller by Martin Fitzpatrick
This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.