Embedding Matplotlib Plots Alongside Other Widgets in PyQt6

How to use Matplotlib canvases as regular widgets in your PyQt6 layouts
Heads up! You've already completed this tutorial.

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, or QGridLayout
  • 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.

python
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:

  1. 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.

  2. Right-click the widget and choose Promote to...

  3. Fill in the promotion dialog:

  4. Promoted class name: MplCanvas
  5. Header file: mplcanvas (this is the Python module name, without .py)

  6. Click Add, then Promote.

  7. Save your .ui file.

Now you need a Python file called mplcanvas.py that contains the MplCanvas class:

python
# 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:

python
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:

python
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:

python
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 QWidget in 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.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

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.

More info Get the book

Martin Fitzpatrick

Embedding Matplotlib Plots Alongside Other Widgets in PyQt6 was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.