All the PyQtGraph examples I've seen use
setCentralWidgetto display the plot, which makes it fill the entire window. How can I control the size and placement of a PyQtGraph plot so it sits alongside other widgets in my application?
When you first start using PyQtGraph with PyQt5, most examples show you setting the plot as the central widget of your main window using self.setCentralWidget(self.graphWidget). This works great for quick demos, but it makes the plot fill the entire window — which isn't what you want when you're building a real application with buttons, labels, and other widgets alongside your graph.
In this tutorial, you'll learn how to control the size and placement of PyQtGraph plots so they fit neatly into your application layout. We'll cover how to embed plots using code-only layouts and how to use Qt Designer to get pixel-perfect control over your graph's size and position.
Why setCentralWidget Takes Over the Window
When you call self.setCentralWidget(self.graphWidget), you're telling the QMainWindow that the plot widget is the central content of the window. Everything else gets pushed aside or hidden. The plot expands to fill all available space.
That's fine for a single-purpose plotting app, but most applications need other widgets too. The solution is to place your plot widget inside a layout alongside your other widgets, just like you would with any other Qt widget.
Embedding a PyQtGraph Plot in a Layout
PyQtGraph's PlotWidget is a regular Qt widget. You can add it to any layout — QVBoxLayout, QHBoxLayout, QGridLayout — just like a QPushButton or QLabel. Here's a complete example that places a plot alongside some controls:
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget,
QVBoxLayout, QHBoxLayout, QPushButton, QLabel
)
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQtGraph in a Layout")
# Create the central widget and main layout.
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# Add a label at the top.
label = QLabel("My Application with a Graph")
main_layout.addWidget(label)
# Create the PyQtGraph plot widget and add it to the layout.
self.graph_widget = pg.PlotWidget()
main_layout.addWidget(self.graph_widget)
# Add some buttons below the graph.
button_layout = QHBoxLayout()
button_layout.addWidget(QPushButton("Start"))
button_layout.addWidget(QPushButton("Stop"))
main_layout.addLayout(button_layout)
# Plot some example data.
self.graph_widget.plot([1, 3, 2, 5, 4, 6, 7], pen="r")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Here we set a plain QWidget as the central widget and give it a QVBoxLayout. The PlotWidget is just one widget among several in that layout. The graph shares the window with the label and buttons.
Controlling the Plot Size with Fixed Dimensions
If you want your graph to be a specific size rather than stretching to fill available space, you can set fixed or maximum dimensions on the PlotWidget using the same methods available on any QWidget:
# Set a fixed size (width, height) in pixels.
self.graph_widget.setFixedSize(400, 300)
Or if you want the plot to resize but only up to a certain limit:
# Set minimum and maximum sizes.
self.graph_widget.setMinimumSize(300, 200)
self.graph_widget.setMaximumSize(600, 400)
Here's a complete example with a fixed-size graph:
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget,
QVBoxLayout, QHBoxLayout, QPushButton, QLabel
)
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Fixed-Size Graph")
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
label = QLabel("This graph has a fixed size of 400x300 pixels")
main_layout.addWidget(label)
self.graph_widget = pg.PlotWidget()
self.graph_widget.setFixedSize(400, 300)
main_layout.addWidget(self.graph_widget)
button_layout = QHBoxLayout()
button_layout.addWidget(QPushButton("Start"))
button_layout.addWidget(QPushButton("Stop"))
main_layout.addLayout(button_layout)
self.graph_widget.plot([1, 3, 2, 5, 4, 6, 7], pen="g")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The graph stays at exactly 400×300 pixels regardless of how you resize the window. The other widgets flow around it as the layout dictates.
Using Stretch Factors to Control Proportions
Another approach is to let the layout handle sizing proportionally using stretch factors. Instead of locking to exact pixel values, you can control how much of the available space each widget gets:
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget,
QVBoxLayout, QPushButton, QLabel
)
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Stretch Factor Graph")
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
label = QLabel("The graph takes up about 2/3 of the vertical space")
main_layout.addWidget(label, stretch=0)
self.graph_widget = pg.PlotWidget()
main_layout.addWidget(self.graph_widget, stretch=2)
button = QPushButton("Do something")
main_layout.addWidget(button, stretch=0)
# Add a second graph that gets less space.
self.graph_widget_2 = pg.PlotWidget()
main_layout.addWidget(self.graph_widget_2, stretch=1)
self.graph_widget.plot([1, 3, 2, 5, 4, 6, 7], pen="r")
self.graph_widget_2.plot([7, 6, 4, 5, 2, 3, 1], pen="b")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The stretch=2 on the first graph and stretch=1 on the second means the first graph gets twice as much vertical space as the second. Widgets with stretch=0 take only the space they need. This gives you proportional sizing that adapts nicely when the window is resized.
Using Qt Designer to Place and Size Your Graph
Qt Designer gives you visual control over widget placement and sizing, which can be much easier than tweaking numbers in code. Since PlotWidget is a PyQtGraph class and not part of the standard Qt widget set, you'll add it to your design using widget promotion.
Setting Up the Design
Open Qt Designer and create a new Main Window. Then:
-
Drag a Graphics View (
QGraphicsView) widget from the widget box onto your form. Position and resize it however you like — this is where your graph will appear. -
Add any other widgets you need (buttons, labels, etc.) and arrange everything using layouts. You can right-click the main window background and select Lay Out Vertically or Lay Out Horizontally to apply a layout to the whole window.
-
If you want the
QGraphicsViewto be a specific size, select it and set theminimumSizeandmaximumSizeproperties in the Property Editor. To lock it at a fixed size, set both to the same value.
Promoting the Widget to PlotWidget
Now you need to tell Qt Designer that this QGraphicsView should actually become a PyQtGraph PlotWidget at runtime:
-
Right-click the
QGraphicsViewand select Promote to.... -
In the dialog, fill in:
- Promoted class name:
PlotWidget -
Header file:
pyqtgraph -
Click Add, then click Promote.
The QGraphicsView now shows as a PlotWidget in the Object Inspector. Save your .ui file (for example, as mainwindow.ui).
Loading the Design in Python
You can load the .ui file directly using uic.loadUi. Here's a complete example assuming you saved your design as mainwindow.ui with a promoted PlotWidget whose object name is graphWidget:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import uic
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("mainwindow.ui", self)
# Access the promoted PlotWidget by its object name.
self.graphWidget.plot([1, 3, 2, 5, 4, 6, 7], pen="r")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The graph appears exactly where you placed it in Qt Designer, at the size you specified. All the size constraints and layout behavior you set up visually are preserved at runtime.
Setting Size Constraints in Qt Designer
To get fine-grained control over the graph's size in Qt Designer, select the promoted widget and look at the Property Editor on the right. The properties you'll find most useful are:
| Property | What it does |
|---|---|
minimumSize |
The smallest the widget can be |
maximumSize |
The largest the widget can be |
sizePolicy |
How the widget behaves when extra space is available |
For a fixed-size graph, set minimumSize and maximumSize to the same width and height. For a graph that resizes but stays within bounds, set them to different values.
The sizePolicy property controls how eager the widget is to grow or shrink relative to its neighbors. Setting the vertical or horizontal policy to Fixed means the widget won't resize in that direction. Expanding means it will try to take extra space when available. Preferred means it'll take its preferred size but can be resized if needed.
A Complete Example
Here's a final complete example that demonstrates a more realistic application layout with a sized graph, built entirely in code:
import sys
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget,
QVBoxLayout, QHBoxLayout,
QPushButton, QLabel, QSpinBox, QGroupBox
)
from PyQt5.QtCore import Qt
import pyqtgraph as pg
import numpy as np
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Data Viewer")
self.resize(800, 500)
central_widget = QWidget()
self.setCentralWidget(central_widget)
# Main horizontal layout: controls on left, graph on right.
main_layout = QHBoxLayout(central_widget)
# Left panel with controls.
controls_group = QGroupBox("Controls")
controls_layout = QVBoxLayout()
controls_group.setLayout(controls_layout)
controls_layout.addWidget(QLabel("Number of points:"))
self.points_spin = QSpinBox()
self.points_spin.setRange(10, 1000)
self.points_spin.setValue(50)
controls_layout.addWidget(self.points_spin)
update_button = QPushButton("Update Plot")
update_button.clicked.connect(self.update_plot)
controls_layout.addWidget(update_button)
controls_layout.addStretch()
# Set the controls panel to a fixed width.
controls_group.setFixedWidth(200)
main_layout.addWidget(controls_group)
# Right side: graph takes remaining space.
right_layout = QVBoxLayout()
self.graph_widget = pg.PlotWidget()
self.graph_widget.setBackground("w")
self.graph_widget.setTitle("Random Data", color="k")
self.graph_widget.setLabel("left", "Value")
self.graph_widget.setLabel("bottom", "Sample")
right_layout.addWidget(self.graph_widget)
self.status_label = QLabel("Ready")
self.status_label.setAlignment(Qt.AlignRight)
right_layout.addWidget(self.status_label)
main_layout.addLayout(right_layout, stretch=1)
# Initial plot.
self.update_plot()
def update_plot(self):
n_points = self.points_spin.value()
data = np.random.normal(size=n_points).cumsum()
self.graph_widget.clear()
self.graph_widget.plot(data, pen=pg.mkPen("b", width=2))
self.status_label.setText(f"Showing {n_points} points")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
This creates a window with a fixed-width control panel on the left and an expanding graph area on the right. The graph fills the remaining space while the controls stay at 200 pixels wide. The status label sits below the graph and takes minimal vertical space.
The same layout could be built visually in Qt Designer using the widget promotion technique described earlier — just drag your widgets into position, apply layouts, set your size constraints, and promote the QGraphicsView to PlotWidget. For a more detailed introduction to PyQtGraph plotting, see our Plotting with PyQtGraph tutorial, and for embedding promoted PyQtGraph widgets into your own custom applications, take a look at Embedding PyQtGraph custom widgets in a Qt app.
Whether you prefer code or Qt Designer, the core idea is the same: treat PlotWidget like any other Qt widget, place it in a layout, and use standard Qt sizing tools to control how much space it gets.
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.