Reusable PySide6/PyQtGraph live plotting widget with toolbar, legend, and smart axis formatting.
Project description
PyQtLabGraph
A powerful, interactive, and premium live plotting library for PySide6/Qt6, based on PyQtGraph.
PyQtLabGraph is built specifically for real-time scientific data visualization, providing an embeddable plot widget, dedicated toolbars, external legend layouts, smart axis formatting, layout persistence, and modern, explicit visual themes.
Table of Contents
- Features
- Interactive Controls
- Installation
- Quick Start
- API Reference
- Advanced pyqtgraph Access
- Visual Styling & Themes
- Performance Optimization
- Project Structure
- Development & Verification
- License
Features
- Real-Time Plotting: High-performance rendering optimized for rapid updates, live sensor streams, or fast oscilloscope-style displays.
- Smart Axis Formatting (
SmartAxisItem):AUTO: Automatic SI-prefix scaling (e.g., scaling raw Hertz tokHz/MHz/GHz).LINEAR: Explicit raw values with user-defined units, bypassing auto-scaling.TIME: Adaptive relative time formatting displaying seconds formatted elegantly asd h min sdepending on zoom level.
- Dedicated External Legend (
PyQtLabGraphLegend):- Displays curve symbols, colors, and labels.
- Interactive: Double-click a curve's legend item to open the Customize dialog immediately focused on that curve. Single-click to toggle curve visibility.
- Configurable orientation: Can be placed vertically (default) or horizontally.
- Integrated Toolbar:
- Action buttons for Show All, rectangle zoom, X-zoom, and Y-zoom.
- Quick autoscale toggle for X and Y axes individually.
- Rolling X-range display with custom size configuration.
- Live PNG export and instant Customize dialog access.
- Modeless Customize Dialog:
- Adjust titles, labels, units, and axis formatting modes.
- Toggle grids, global anti-aliasing, downsampling, clip-to-view, and adaptive performance.
- Manage individual curves: toggling visibility, line width, line colors, marker styles (circle, square, cross, diamond, etc.), size, and borders.
- Live Preview: All configuration edits preview immediately in the plot in real-time, and revert instantly if the user clicks Cancel.
- Layout Persistence: Save/Load all layout configurations (visual properties, themes, active ranges, curve states) to a shared versioned JSON file.
- Adaptive Performance: Automatic visual simplification when rendering very dense datasets to avoid UI lag.
Interactive Controls
PyQtLabGraph introduces advanced viewport mouse controls on top of the standard PyQtGraph mouse interactions:
- Mouse Drag (Left Click): Pans the view in the selected tool mode.
- Mouse Drag (Right Click): Zooms X and Y scale dynamically (drag left/right for X, up/down for Y).
- Mouse Wheel: Zooms both X and Y axes centered on the cursor position.
- Shift + Mouse Wheel: Zooms X-axis only, preserving the Y-axis range.
- Ctrl + Mouse Wheel: Zooms Y-axis only, preserving the X-axis range.
- Double Click Axis: Opens a quick manual range pop-up directly underneath the cursor for entering exact values.
Installation
Install PyQtLabGraph from PyPI:
pip install pyqtlabgraph
Or install it directly from the repository source:
pip install .
For development installations, make sure you have the runtime dependencies installed:
pip install PySide6 pyqtgraph
Quick Start
You can check out how to use the library using the packaged demo files in the examples/ directory:
-
Minimal Example (One random walk curve, basic legend, and toolbar):
python examples/demo_minimal.py -
Thermostat Simulation Demo (Realistic simulated heating/cooling loop, horizontal legend, showing toolbar states and custom styling integration):
python examples/demo_thermostat.py -
Time Domain & FFT Demo (Two independent synchronized plots with separate controls):
python examples/demo_time_fft.py -
Host Application Styling Comparison (Integrates with dark mode styling packages like
qdarktheme):python examples/demo_thermostat_qdarktheme.py
API Reference
PyQtLabGraphWidget Constructor
Initialize the widget, typically inside a host QMainWindow or custom container layout.
from pathlib import Path
from PySide6.QtCore import Qt
from pyqtlabgraph import PyQtLabGraphWidget
self.plot = PyQtLabGraphWidget(
plot_container=self.ui.plotContainer, # Anchor QWidget for the main plot
toolbar_container=self.ui.toolbarContainer, # Anchor QWidget for the toolbar (optional)
legend_container=self.ui.legendContainer, # Anchor QWidget for the legend (optional)
plot_identifier="my-unique-plot-id", # Identifier key for layout persistence
layout_path=Path("plot_layouts.json"), # Target layout file (optional)
show_toolbar=True, # Show toolbar (default: True)
show_legend=True, # Show legend (default: True if container present)
legend_orientation=Qt.Orientation.Horizontal,# Horizontal or Vertical legend
rolling_window_size=300.0, # Initial rolling X window size (default: 300.0)
theme="dark", # Initial theme (default: neutral/light)
plot_style="dark", # Initial curve style palette (default: light)
show_component_frames=True, # Draw fallback border frames if no stylesheet exists
)
Constructor Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
plot_container |
QWidget |
Required | Host widget that will contain the embedded Pyqtgraph canvas. |
toolbar_container |
QWidget |
None |
Host widget where the custom toolbar will be injected. |
legend_container |
QWidget |
None |
Host widget where the legend will be injected. |
plot_identifier |
str |
Required | Stable, unique key for the plot. Crucial for JSON layout file mapping. |
layout_path |
str | Path |
None |
Path to the layout save file. Activates auto layout features. |
show_toolbar |
bool |
True |
If False, disables creation of the toolbar even if a container is supplied. |
show_legend |
bool |
None |
Overrides legend display. Defaults to True if legend_container is given. |
legend_orientation |
Qt.Orientation |
Qt.Orientation.Vertical |
Orientation of legend items: Qt.Orientation.Vertical or Qt.Orientation.Horizontal. |
rolling_window_size |
float |
300.0 |
Initial width of the rolling X-window. |
theme |
str | PyQtLabGraphTheme |
None |
Active background/grid theme name ("light", "dark", "light-solarized", "dark-solarized"). |
plot_style |
str | PyQtLabGraphPlotStyle |
None |
Active curve styling palette name ("light", "dark", "solarized"). |
show_component_frames |
bool |
True |
Draw palette-aware layout frames around containers in the absence of a global stylesheet. |
Core Plotting Methods
Use these methods to manage curves and feed data into the widget:
plot(key: str, x: ArrayLike, y: ArrayLike = None, label: str = None, style: CurveStyle = None)
Primary entry point. Creates or updates a curve identified bykey. Ifxis the only array passed, it's treated as Y-data with X generated as indices.add_curve(key: str, label: str = None, style: CurveStyle = None)
Registers a new curve key without passing data. Used to initialize legend entries early.set_data(key: str, x: ArrayLike = None, y: ArrayLike = None, **kwargs)
Updates coordinates of an existing curvekey. Safe to passxandyseparately. Supports keyword parameters mapping topyqtgraph.PlotDataItem.setData(...).add_point(key: str, x: float, y: float)
Appends a single data point to the curve. Extremely useful for real-time live sensor updates.curve_data(key: str) -> tuple[np.ndarray, np.ndarray]
Retrieves current coordinates stored in the underlying PyQtGraphPlotDataItemfor the curve.curve_style(key: str) -> CurveStyle
Returns the current curve style object.set_curve_style(key: str, style: CurveStyle)
Applies a newCurveStyleto the given curve.set_curve_visible(key: str, visible: bool)
Toggles rendering of the curve in the canvas and marks its checkbox state in the legend.
Layout & Customization Methods
Configure views, axes, limits, and serialize settings:
set_axis_labels(x_label: str, y_label: str, x_units: str = None, y_units: str = None, x_mode: AxisMode = None, y_mode: AxisMode = None)
Updates axis titles, units, and tick representation modes (AxisMode.AUTO,AxisMode.LINEAR,AxisMode.TIME).get_x_range() -> tuple[float, float]/get_y_range() -> tuple[float, float]
Gets active viewport limits.apply_manual_x_limits(xmin: float, xmax: float)/apply_manual_y_limits(ymin: float, ymax: float)
Manually sets limits, deactivating automatic scaling or rolling window modes.request_rolling_x(enabled: bool)
Enables/disables the rolling X-window.set_rolling_window_size(size: float)
Updates the rolling window size.request_autoscale_x()/request_autoscale_y()
Instantly scales the corresponding axis to fit the current visible data bounds.request_show_all()
Rescales both axes to fit all data.set_theme(theme: str | PyQtLabGraphTheme)
Applies a background/grid theme.set_plot_style(style: str | PyQtLabGraphPlotStyle)
Sets the active plot style palette for new curves.apply_plot_style(style: str | PyQtLabGraphPlotStyle)
Updates all existing curves to use the color palette of the target plot style.save_layout()/load_layout()
Manually writes/restores layout state to/from the file set inlayout_path.show_customize_dialog(curve_key: str = None)
Launches the modeless Customize dialog. Ifcurve_keyis supplied, it opens directly on the tab editing that curve.
Advanced pyqtgraph Access
PyQtLabGraph stays out of the way when advanced customization is required. You can bypass our high-level wrappers and talk directly to the underlying PyQtGraph library components:
# Access native pyqtgraph objects
native_widget = self.plot.native_plot_widget # pg.PlotWidget
native_item = self.plot.native_plot_item # pg.PlotItem
native_view = self.plot.native_view_box # pg.ViewBox
# Add native items to the canvas
native_item.addItem(my_custom_infinite_line)
# Retrieve raw PlotDataItem references
raw_curve_item = self.plot.curve_item("sensor_1") # pg.PlotDataItem
raw_curve_item.setClickable(True)
Visual Styling & Themes
Themes
A theme governs the plot data canvas, background, and gridlines:
light: Neutral light background with grey gridlines.dark: High-contrast dark grey/black background.light-solarized: Classic solarized-cream aesthetic.dark-solarized: Deep blue-green solarized aesthetic.
self.plot.set_theme("dark-solarized")
Plot Styles
A plot style determines the palette (line colors, markers, widths) mapped to curves:
light: Highly visible color cycle optimized for light background themes.dark: Vibrant color cycle optimized for dark background themes.solarized: Palette adhering to the solarized styling standard.
self.plot.set_plot_style("solarized")
Host Application Styling
PyQtLabGraph widgets are transparent outside the ViewBox canvas. All surrounding chrome (toolbar buttons, external legend container, customize dialog, pop-up menus) inherits the host Qt application's styling. You can apply modern styling frameworks to your host application (like qdarktheme or QCommonStyle), and PyQtLabGraph's chrome will adapt automatically:
# Example: Recoloring toolbar icons based on host application style change
import qdarktheme
app.setStyleSheet(qdarktheme.load_stylesheet("dark"))
The toolbar's packaged PNG masks will automatically adapt to match light/dark icon palettes of the active Qt window style.
Performance Optimization
For dense, high-frequency datasets, PyQtLabGraph provides several levels of performance optimization:
- Downsampling: Dynamically reduces the number of points drawn by grouping dense data points (activated via customize dialog).
- Clip to View: Cuts off calculations for data coordinates lying outside the current visible X range (activated via customize dialog).
- Adaptive Rendering (Adaptive Performance):
When the number of visible points on the screen exceeds a high threshold (e.g., 20,000 points), PyQtLabGraph temporarily disables antialiasing and markers to maintain smooth panning and zooming. When you zoom back in and the point count falls below a lower threshold (e.g., 10,000 points), these detailed styling properties are automatically restored.
Project Structure
├── pyqtlabgraph/ # Main library package
│ ├── __init__.py # Public exports & versioning
│ ├── widget.py # Main PyQtLabGraphWidget and API wrapping
│ ├── dialogs.py # Modeless Customize dialog & popups
│ ├── layouts.py # JSON Layout save/load mechanics
│ ├── toolbar.py # Toolbar buttons, export, and mode controllers
│ ├── legend.py # External interactive PyQtLabGraphLegend
│ ├── axis.py # SmartAxisItem tick formatting implementation
│ ├── models.py # Core dataclasses (CurveState, InteractionState)
│ ├── styles.py # Curve style configurations and palettes
│ ├── themes.py # Background themes and color registries
│ ├── qt_styles.py # Standard fallback borders and QSS wrappers
│ └── assets/ # PNG icon assets used by the toolbar
├── tests/ # Standalone smoke test suite
├── examples/ # Packaged demo and example files
│ ├── demo_minimal.py # Getting started minimal walkthrough
│ ├── demo_thermostat.py # Main thermostat feature demo
│ └── demo_time_fft.py # Grid/dual plot designer layout demo
└── pyproject.toml # Build system and package metadata
Development & Verification
Tests are located in the tests/ directory and can be executed via a unified test runner. Run this command after any code changes to verify syntax, assets, and UI state:
python3 tests/run_smoke_checks.py
To run a specific smoke check, execute it directly with Qt configured in offscreen mode (useful for headless CI environments):
QT_QPA_PLATFORM=offscreen python3 tests/smoke_customize_dialog.py
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyqtlabgraph-0.1.0.tar.gz.
File metadata
- Download URL: pyqtlabgraph-0.1.0.tar.gz
- Upload date:
- Size: 269.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35fd95eb465f92527d594dcd6b14d20f62417367e4c90c4d5346e2a5d1b24376
|
|
| MD5 |
0ea40656e51f9bd1b2dfa893eb1a215f
|
|
| BLAKE2b-256 |
6a47abd0040b874124b638006fe32787dfea6dea43727d84cae705067a187872
|
Provenance
The following attestation bundles were made for pyqtlabgraph-0.1.0.tar.gz:
Publisher:
publish.yml on choberg/pyqtlabgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyqtlabgraph-0.1.0.tar.gz -
Subject digest:
35fd95eb465f92527d594dcd6b14d20f62417367e4c90c4d5346e2a5d1b24376 - Sigstore transparency entry: 1679443122
- Sigstore integration time:
-
Permalink:
choberg/pyqtlabgraph@c7eb7962152f1c69f9dc0a7dd446078c0c9fdcfa -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/choberg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c7eb7962152f1c69f9dc0a7dd446078c0c9fdcfa -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyqtlabgraph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyqtlabgraph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 267.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b61cd3deadd965237538ec41ec998d0fa6654337b94d53f03caf654eaffebd55
|
|
| MD5 |
e33c197e709b2a8b2a003e43e8b53706
|
|
| BLAKE2b-256 |
a0718e58fb0072c5ec915c43d24b83001df592385c59521823775e4f91b04fef
|
Provenance
The following attestation bundles were made for pyqtlabgraph-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on choberg/pyqtlabgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyqtlabgraph-0.1.0-py3-none-any.whl -
Subject digest:
b61cd3deadd965237538ec41ec998d0fa6654337b94d53f03caf654eaffebd55 - Sigstore transparency entry: 1679443328
- Sigstore integration time:
-
Permalink:
choberg/pyqtlabgraph@c7eb7962152f1c69f9dc0a7dd446078c0c9fdcfa -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/choberg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c7eb7962152f1c69f9dc0a7dd446078c0c9fdcfa -
Trigger Event:
release
-
Statement type: