Plotting time series data with PyQtGraph

Display datetime data on PyQtGraph plot axes, including when using Qt Designer
Heads up! You've already completed this tutorial.

How do I plot time series data with date/time axis labels in PyQtGraph, and how can I get this working when using Qt Designer's promoted widgets?

When working with real-world data, you'll often need to plot values against timestamps — stock prices over days, sensor readings over hours, or server logs over minutes. PyQtGraph makes this straightforward with its DateAxisItem, which converts Unix timestamps into human-readable date and time labels on your plot axis.

In this tutorial, we'll walk through how to plot time series data using PyQtGraph, first in a simple standalone script, then inside a Qt Designer–promoted PlotWidget. By the end, you'll have a complete, working example you can adapt for your own projects.

What is a Unix timestamp?

Before we start plotting, it helps to understand how PyQtGraph handles dates. PyQtGraph doesn't work with Python datetime objects directly. Instead, it uses Unix timestamps — the number of seconds since January 1, 1970 (UTC).

Python's datetime module can convert between human-readable dates and timestamps easily:

python
from datetime import datetime

dt = datetime(2025, 3, 15, 10, 30, 0)
timestamp = dt.timestamp()
print(timestamp)  # e.g. 1742035800.0

When you pass these timestamp values as your x-axis data, PyQtGraph's DateAxisItem will format them into readable date/time labels automatically.

A simple time series plot

Let's start with a minimal example that plots some data points against dates. If you're new to PyQtGraph, you may want to read our introduction to plotting with PyQtGraph first.

python
import sys
from datetime import datetime

import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication

app = QApplication(sys.argv)

# Create some sample time series data.
timestamps = [
    datetime(2025, 1, 1).timestamp(),
    datetime(2025, 2, 1).timestamp(),
    datetime(2025, 3, 1).timestamp(),
    datetime(2025, 4, 1).timestamp(),
    datetime(2025, 5, 1).timestamp(),
]
values = [10, 25, 18, 35, 30]

# Create a DateAxisItem for the bottom axis.
date_axis = pg.DateAxisItem()

# Create the PlotWidget, passing the DateAxisItem.
plot_widget = pg.PlotWidget(axisItems={"bottom": date_axis})
plot_widget.setWindowTitle("Time Series Example")
plot_widget.setLabel("left", "Value")
plot_widget.setLabel("bottom", "Date")
plot_widget.plot(timestamps, values, pen="b", symbol="o")

plot_widget.show()
sys.exit(app.exec_())

Run this and you'll see a plot with nicely formatted date labels on the x-axis. The DateAxisItem handles all the formatting, choosing appropriate labels based on the zoom level (years, months, days, hours, etc.).

Time series plot with DateAxisItem

Using DateAxisItem inside a QMainWindow

In most real applications, you won't just show a bare PlotWidget — you'll embed it inside a window with other widgets. Here's how that looks inside a QMainWindow:

PyQt/PySide Development Services — Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.

Find out More

python
import sys
from datetime import datetime

import pyqtgraph as pg
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Time Series in QMainWindow")

        # Create sample data.
        self.timestamps = [
            datetime(2025, 1, 1).timestamp(),
            datetime(2025, 2, 1).timestamp(),
            datetime(2025, 3, 1).timestamp(),
            datetime(2025, 4, 1).timestamp(),
            datetime(2025, 5, 1).timestamp(),
            datetime(2025, 6, 1).timestamp(),
        ]
        self.values = [12, 28, 15, 33, 42, 38]

        # Create DateAxisItem and PlotWidget.
        date_axis = pg.DateAxisItem()
        self.graph_widget = pg.PlotWidget(axisItems={"bottom": date_axis})
        self.graph_widget.setLabel("left", "Temperature (°C)")
        self.graph_widget.setLabel("bottom", "Date")
        self.graph_widget.setTitle("Monthly Temperatures")

        self.graph_widget.plot(
            self.timestamps, self.values, pen="r", symbol="o", symbolBrush="r"
        )

        # Set up layout.
        layout = QVBoxLayout()
        layout.addWidget(self.graph_widget)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

This works exactly as you'd expect. The DateAxisItem is passed in when creating the PlotWidget, and the widget is added to the window layout like any other Qt widget.

The Qt Designer challenge

Here's where things get a bit tricky, and where many people get stuck. When you use Qt Designer to design your interface, you typically promote a QGraphicsView (or QWidget) to pg.PlotWidget. Qt Designer creates the widget for you — but it doesn't give you any way to pass axisItems as a constructor argument.

That's why this pattern doesn't work when using Qt Designer:

python
# This works when YOU create the widget...
self.graph_widget = pg.PlotWidget(axisItems={"bottom": date_axis})

# ...but if Qt Designer already created self.graphicsView,
# you can't pass constructor arguments to it.

The widget already exists by the time your __init__ method runs. You need a different approach.

Replacing the axis after creation

The solution is to set the DateAxisItem on the plot after the widget has been created. You can do this by calling setAxisItems():

python
date_axis = pg.DateAxisItem()
self.graphicsView.setAxisItems({"bottom": date_axis})

The setAxisItems() method replaces the existing axis with your new one. This works whether the PlotWidget was created in your code or by Qt Designer's generated UI file.

Using DateAxisItem with Qt Designer

Let's put this into practice with a complete Qt Designer workflow.

Setting up the .ui file

  1. Open Qt Designer and create a new Main Window.
  2. Drag a QGraphicsView onto the central widget.
  3. Right-click the QGraphicsView and select Promote to....
  4. Fill in the promotion dialog:
  5. Promoted class name: PlotWidget
  6. Header file: pyqtgraph
  7. Click Add, then Promote.
  8. Save the file as mainwindow.ui.

If you're not familiar with promoting widgets in Qt Designer, the basic idea is that you're telling Qt to use pyqtgraph.PlotWidget instead of the plain QGraphicsView at runtime. For a full walkthrough of embedding custom widgets via promotion, see our guide to embedding PyQtGraph in Qt applications.

The complete code

Here's a full working example that loads a .ui file and adds a time series plot with proper date axis labels:

python
import sys
from datetime import datetime

import pyqtgraph as pg
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("mainwindow.ui", self)

        # Replace the bottom axis with a DateAxisItem.
        # This works even though Qt Designer already created the widget.
        date_axis = pg.DateAxisItem()
        self.graphicsView.setAxisItems({"bottom": date_axis})

        # Create sample time series data.
        timestamps = [
            datetime(2025, 1, 15).timestamp(),
            datetime(2025, 2, 15).timestamp(),
            datetime(2025, 3, 15).timestamp(),
            datetime(2025, 4, 15).timestamp(),
            datetime(2025, 5, 15).timestamp(),
            datetime(2025, 6, 15).timestamp(),
        ]
        values = [22, 19, 25, 31, 37, 42]

        # Configure and plot.
        self.graphicsView.setLabel("left", "Value")
        self.graphicsView.setLabel("bottom", "Date")
        self.graphicsView.setTitle("Time Series from Qt Designer")
        self.graphicsView.plot(timestamps, values, pen="g", symbol="o")


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

The promoted widget from Qt Designer is accessible as self.graphicsView (or whatever object name you gave it in Designer). After loading the UI, we call setAxisItems() to swap in the DateAxisItem — and from that point on, everything works as normal.

If you renamed the widget in Qt Designer (for example, to plotWidget), use that name instead: self.plotWidget.setAxisItems(...).

Without Qt Designer

If you're not using Qt Designer but still want to build a time series plot inside a custom window class, you have two equally valid options.

Option 1: Pass axisItems at creation time.

python
date_axis = pg.DateAxisItem()
self.graph_widget = pg.PlotWidget(axisItems={"bottom": date_axis})

Option 2: Create the widget first, then replace the axis.

python
self.graph_widget = pg.PlotWidget()
date_axis = pg.DateAxisItem()
self.graph_widget.setAxisItems({"bottom": date_axis})

Both produce identical results. Option 2 is useful to know because it's the same pattern you need when working with Qt Designer.

Complete example with live updating data

To bring everything together, here's a more realistic example. This creates a time series plot that updates with new data points every second, simulating a live data feed — like a temperature sensor or stock ticker. The live update is driven by a QTimer, which calls our update_plot method at regular intervals. For more on handling background tasks and timers in PyQt5, see our multithreading with QThreadPool tutorial.

python
import sys
from datetime import datetime
from collections import deque

import numpy as np
import pyqtgraph as pg
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget


class LiveTimeSeriesWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Live Time Series Plot")
        self.resize(800, 400)

        # Store the last 60 data points.
        self.max_points = 60
        self.timestamps = deque(maxlen=self.max_points)
        self.values = deque(maxlen=self.max_points)

        # Create the plot with a DateAxisItem.
        date_axis = pg.DateAxisItem()
        self.graph_widget = pg.PlotWidget(axisItems={"bottom": date_axis})
        self.graph_widget.setLabel("left", "Sensor Value")
        self.graph_widget.setLabel("bottom", "Time")
        self.graph_widget.setTitle("Live Sensor Data")
        self.graph_widget.addLegend()

        # Create the plot data item (empty for now).
        self.data_line = self.graph_widget.plot(
            [], [], pen=pg.mkPen("c", width=2), name="Sensor 1"
        )

        # Layout.
        layout = QVBoxLayout()
        layout.addWidget(self.graph_widget)
        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        # Timer to add new data every second.
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_plot)
        self.timer.start(1000)

        # Seed with a starting value.
        self.current_value = 20.0

    def update_plot(self):
        # Generate a new data point.
        now = datetime.now().timestamp()
        self.current_value += np.random.normal(0, 0.5)  # Random walk.

        self.timestamps.append(now)
        self.values.append(self.current_value)

        # Update the plot.
        self.data_line.setData(list(self.timestamps), list(self.values))


app = QApplication(sys.argv)
window = LiveTimeSeriesWindow()
window.show()
sys.exit(app.exec_())

Run this and you'll see data points appearing in real time, with the x-axis showing the current time formatted by DateAxisItem. As the window fills with 60 points, older data scrolls off the left side thanks to the deque with a maxlen.

Summary

Plotting time series data in PyQtGraph comes down to two things:

  1. Use Unix timestamps for your x-axis values. Convert from Python datetime objects using .timestamp().
  2. Use DateAxisItem to display those timestamps as formatted dates on the axis.

When creating the PlotWidget yourself, you can pass axisItems={"bottom": date_axis} directly. When working with Qt Designer (where the widget is already created for you), use setAxisItems() to swap in the DateAxisItem after loading the UI. Both approaches give you the same result — a clean, readable time series plot with properly formatted date and time labels.

If you also want to plot with Matplotlib inside a PyQt5 application, check out our Matplotlib plotting tutorial.

Over 15,000 developers have bought Create GUI Applications with Python & Qt!
Create GUI Applications with Python & Qt6
Take a look

Downloadable ebook (PDF, ePub) & Complete Source code

Also available from Amazon Paperback

[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]
Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create GUI Applications with Python & Qt5 by Martin Fitzpatrick

(PyQt5 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!

More info Get the book

Martin Fitzpatrick

Plotting time series data with PyQtGraph 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.