PyQtGraph makes it straightforward to create bar charts using BarGraphItem, and once you understand the basics, you can extend the same approach to build grouped and stacked bar charts. In this tutorial, we'll walk through creating a simple bar chart, then progress to grouped bars (multiple series side by side) and stacked bars (series on top of each other).
A Simple Bar Chart
Before getting into grouped and stacked charts, let's start with a single bar chart so we have a foundation to build on.
BarGraphItem takes a few key parameters:
x— the x positions of the barsheight— the height of each barwidth— how wide each bar should bebrush— the fill color
Here's a minimal example:
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
win = pg.plot()
win.setWindowTitle("Simple Bar Chart")
x = [1, 2, 3, 4, 5]
heights = [10, 25, 15, 30, 20]
bar = pg.BarGraphItem(x=x, height=heights, width=0.6, brush="steelblue")
win.addItem(bar)
sys.exit(app.exec())
Running this gives you five blue bars. The x values control where the bars sit along the horizontal axis, height sets how tall each bar is, and width controls the bar thickness.
Creating a Grouped Bar Chart
A grouped bar chart places multiple series of bars side by side at each position on the x-axis. Think of comparing sales figures for different products across several months — each month has a cluster of bars, one per product.
The trick is to offset each series slightly along the x-axis so the bars sit next to each other rather than on top of one another.
Let's say we have three categories and two data series. We'll use a bar width of 0.3 and shift each series by that amount:
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
win = pg.plot()
win.setWindowTitle("Grouped Bar Chart")
# Data
categories = [1, 2, 3, 4, 5]
series_a = [20, 35, 30, 35, 27]
series_b = [25, 32, 34, 20, 25]
x = np.array(categories, dtype=float)
width = 0.3
# Offset each series so they sit side by side
bar_a = pg.BarGraphItem(x=x - width / 2, height=series_a, width=width, brush="#4a86c8", name="Series A")
bar_b = pg.BarGraphItem(x=x + width / 2, height=series_b, width=width, brush="#e85d04", name="Series B")
win.addItem(bar_a)
win.addItem(bar_b)
# Add a legend
win.addLegend()
sys.exit(app.exec())
Each BarGraphItem gets its own set of x positions, shifted left or right by half the bar width. This keeps the group centered on the original x position.
For two series, the offsets are -width/2 and +width/2. If you had three series, you'd use -width, 0, and +width:
bar_a = pg.BarGraphItem(x=x - width, height=series_a, width=width, brush="#4a86c8")
bar_b = pg.BarGraphItem(x=x, height=series_b, width=width, brush="#e85d04")
bar_c = pg.BarGraphItem(x=x + width, height=series_c, width=width, brush="#2a9d8f")
The general pattern: center the group of bars around each x tick by spreading them evenly.
Creating a Stacked Bar Chart
A stacked bar chart places one series on top of another at the same x position. This is useful when you want to show how individual parts contribute to a total.
PyQtGraph's BarGraphItem has a y0 parameter that sets the baseline (bottom edge) of each bar. By setting the y0 of the second series to be the height of the first series, the bars stack up.
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
win = pg.plot()
win.setWindowTitle("Stacked Bar Chart")
# Data
categories = [1, 2, 3, 4, 5]
series_a = np.array([20, 35, 30, 35, 27])
series_b = np.array([25, 32, 34, 20, 25])
x = np.array(categories, dtype=float)
width = 0.6
# First series sits on the baseline (y0 defaults to 0)
bar_a = pg.BarGraphItem(x=x, height=series_a, width=width, brush="#4a86c8", name="Series A")
# Second series sits on top of the first
bar_b = pg.BarGraphItem(x=x, height=series_b, width=width, y0=series_a, brush="#e85d04", name="Series B")
win.addItem(bar_a)
win.addItem(bar_b)
win.addLegend()
sys.exit(app.exec())
The first series uses the default baseline of 0. The second series uses y0=series_a, which places each bar's bottom edge at the top of the corresponding bar in series A. The height of each bar in series B is still relative — it represents how much that segment adds to the stack.
To add a third series, set its y0 to the sum of the first two:
series_c = np.array([15, 10, 20, 15, 18])
bar_c = pg.BarGraphItem(
x=x, height=series_c, width=width,
y0=series_a + series_b,
brush="#2a9d8f", name="Series C"
)
win.addItem(bar_c)
Adding Custom Axis Labels
Numeric x-axis labels (1, 2, 3...) aren't always what you need. You'll often want text labels like month names or product categories. You can achieve this with a custom axis using a dictionary that maps tick positions to label strings.
Here's how to set custom x-axis tick labels:
# Define tick labels
ticks = {1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May"}
# Get the bottom axis and set ticks
ax = win.getAxis("bottom")
ax.setTicks([list(ticks.items())])
The setTicks method expects a list of tick levels. Each level is a list of (position, label) tuples. Passing a single level like this gives you one row of labels.
Complete Working Example
Let's put everything together into a complete PyQt6 application that shows a grouped bar chart with custom labels, a legend, and a title. If you're new to building PyQt6 applications, you may want to start with creating your first window before diving in.
import sys
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets, QtCore
class BarChartWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Grouped Bar Chart — PyQtGraph")
self.resize(800, 500)
# Create the plot widget
self.plot_widget = pg.PlotWidget()
self.setCentralWidget(self.plot_widget)
# Enable the legend
self.plot_widget.addLegend()
# Title and labels
self.plot_widget.setTitle("Quarterly Sales by Product", size="14pt")
self.plot_widget.setLabel("left", "Revenue ($k)")
self.plot_widget.setLabel("bottom", "Quarter")
# Data
quarters = np.array([1, 2, 3, 4], dtype=float)
product_a = [120, 150, 180, 200]
product_b = [90, 130, 160, 170]
product_c = [60, 80, 110, 140]
width = 0.25
# Create bars, offset for grouping
bar_a = pg.BarGraphItem(
x=quarters - width, height=product_a,
width=width, brush="#4a86c8", name="Product A"
)
bar_b = pg.BarGraphItem(
x=quarters, height=product_b,
width=width, brush="#e85d04", name="Product B"
)
bar_c = pg.BarGraphItem(
x=quarters + width, height=product_c,
width=width, brush="#2a9d8f", name="Product C"
)
self.plot_widget.addItem(bar_a)
self.plot_widget.addItem(bar_b)
self.plot_widget.addItem(bar_c)
# Custom x-axis tick labels
ticks = {1: "Q1", 2: "Q2", 3: "Q3", 4: "Q4"}
ax = self.plot_widget.getAxis("bottom")
ax.setTicks([list(ticks.items())])
# Start the y-axis at 0
self.plot_widget.setYRange(0, 220)
app = QtWidgets.QApplication(sys.argv)
window = BarChartWindow()
window.show()
sys.exit(app.exec())
This gives you a clean, professional-looking grouped bar chart with three products compared across four quarters.

Complete Stacked Bar Example
And here's the same data displayed as a stacked bar chart instead:
import sys
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
class StackedBarChartWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Stacked Bar Chart — PyQtGraph")
self.resize(800, 500)
self.plot_widget = pg.PlotWidget()
self.setCentralWidget(self.plot_widget)
self.plot_widget.addLegend()
self.plot_widget.setTitle("Quarterly Sales by Product (Stacked)", size="14pt")
self.plot_widget.setLabel("left", "Revenue ($k)")
self.plot_widget.setLabel("bottom", "Quarter")
# Data
quarters = np.array([1, 2, 3, 4], dtype=float)
product_a = np.array([120, 150, 180, 200])
product_b = np.array([90, 130, 160, 170])
product_c = np.array([60, 80, 110, 140])
width = 0.6
# Stack the bars
bar_a = pg.BarGraphItem(
x=quarters, height=product_a,
width=width, brush="#4a86c8", name="Product A"
)
bar_b = pg.BarGraphItem(
x=quarters, height=product_b,
width=width, y0=product_a, brush="#e85d04", name="Product B"
)
bar_c = pg.BarGraphItem(
x=quarters, height=product_c,
width=width, y0=product_a + product_b, brush="#2a9d8f", name="Product C"
)
self.plot_widget.addItem(bar_a)
self.plot_widget.addItem(bar_b)
self.plot_widget.addItem(bar_c)
# Custom x-axis tick labels
ticks = {1: "Q1", 2: "Q2", 3: "Q3", 4: "Q4"}
ax = self.plot_widget.getAxis("bottom")
ax.setTicks([list(ticks.items())])
# Adjust y-axis to fit stacked totals
max_height = max(product_a + product_b + product_c)
self.plot_widget.setYRange(0, max_height + 20)
app = QtWidgets.QApplication(sys.argv)
window = StackedBarChartWindow()
window.show()
sys.exit(app.exec())
Summary
Both grouped and stacked bar charts in pyqtgraph use the same BarGraphItem — the difference is just how you position each series:
| Chart Type | Technique |
|---|---|
| Grouped | Offset each series along the x-axis so bars sit side by side |
| Stacked | Use the y0 parameter to place each series on top of the previous one |
Once you're comfortable with these patterns, you can combine them with pyqtgraph's other features — tooltips, interactive zooming, real-time updates — to build rich, dynamic data visualizations right inside your PyQt6 applications. For more on plotting with pyqtgraph, see our PyQtGraph plotting tutorial. You can also embed pyqtgraph plots as custom widgets within larger applications, or explore plotting with Matplotlib as an alternative charting approach.
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.