PyQtGraph library providing thread-safe plot curves with underlying (ring) buffers.
Project description
DvG_PyQtGraph_ThreadSafe
PyQtGraph library providing thread-safe plot curves with underlying (ring) buffers.
Supports PyQt5, PyQt6, PySide2 and PySide6.
Installation:
pip install dvg-pyqtgraph-threadsafe
You must also ensure a Qt library is installed in your Python environment as this library will not install one for you. Pick one (personal recommendation PySide6):
pip install pyqt5 pip install pyqt6 pip install pyside2 pip install pyside6
Futhermore, you might want to enable OpenGL hardware accelerated plotting by installing PyOpenGL:
pip install pyopengl
Useful links
Demos can be found in the demos folder.
Benchmark tests and results can be found in the benchmark folder.
Important notes on the specific use-case where another thread is actively requesting data at a high rate from an external device (e.g. an Arduino) to be pushed into a ThreadSafeCurve can be found here.
Overview
Classes HistoryChartCurve, BufferedPlotCurve & PlotCurve wrap around a pyqtgraph.PlotDataItem instance, called a curve for convenience. Data can be safely appended or set from out of any thread.
The (x, y)-curve data is buffered internally to the class, relying on either a circular/ring buffer or a regular array buffer:
- HistoryChartCurve
Ring buffer. The plotted x-data will be shifted such that the right-side is always set to 0. I.e., when x denotes time, the data is plotted backwards in time, hence the name history chart. The most recent data is on the right-side of the ring buffer.
- BufferedPlotCurve
Ring buffer. Data will be plotted as is. Can also act as a Lissajous figure.
- PlotCurve
Regular array buffer. Data will be plotted as is.
Usage
import sys from qtpy import QtWidgets import pyqtgraph as pg from dvg_pyqtgraph_threadsafe import HistoryChartCurve class MainWindow(QtWidgets.QWidget): def __init__(self, parent=None, **kwargs): super().__init__(parent, **kwargs) self.gw = pg.GraphicsLayoutWidget() self.plot_1 = self.gw.addPlot() # Create a HistoryChartCurve and have it wrap around a new # PlotDataItem as set by argument `linked_curve`. self.tscurve_1 = HistoryChartCurve( capacity=5, linked_curve=self.plot_1.plot(pen=pg.mkPen('r')), ) grid = QtWidgets.QGridLayout(self) grid.addWidget(self.gw) app = QtWidgets.QApplication(sys.argv) window = MainWindow() # The following line could have been executed from inside of another thread: window.tscurve_1.extendData([1, 2, 3, 4, 5], [10, 20, 30, 20, 10]) # Draw the curve from out of the main thread window.tscurve_1.update() window.show() sys.exit(app.exec())
Benchmark
If you intend to use this library to plot 100.000s of points at a high frame rate on your integrated GPU instead of on a dedicated (performance) GPU, you might run into performance issues. Even when OpenGL hardware acceleration is enabled.
I recommend you run the performance benchmark found in the benchmark folder. It can test for different PyQtGraph versions and Qt libraries on your GPU of choice. I have found that the older pyqtgraph 0.11 library sometimes results in a better performance than pyqtgraph 0.12 on integrated GPUs. See benchmark results.
API
Class ThreadSafeCurve
ThreadSafeCurve(
capacity: int | None,
linked_curve: pyqtgraph.PlotDataItem,
shift_right_x_to_zero: bool = False,
use_ringbuffer=None,
)
Class HistoryChartCurve
HistoryChartCurve(
capacity: int,
linked_curve: pyqtgraph.PlotDataItem,
)
Class BufferedPlotCurve
BufferedPlotCurve(
capacity: int,
linked_curve: pyqtgraph.PlotDataItem,
)
Class PlotCurve
PlotCurve(
capacity: int,
linked_curve: pyqtgraph.PlotDataItem,
)
API Extras
Class LegendSelect
LegendSelect(
linked_curves: Sequence[pyqtgraph.PlotDataItem | ThreadSafeCurve],
hide_toggle_button: bool = False,
box_bg_color: QtGui.QColor = QtGui.QColor(0, 0, 0),
box_width: int = 40,
box_height: int = 23,
parent=None,
)
Class PlotManager
PlotManager(
parent=None,
)
Changelog
3.4.0 (2024-06-24)
Code quality improvements:
Using qtpy library instead of my own Qt5/6 mechanism
Using f-strings
Extended API and docstrings, like on PlotManager.
Arguments linked_curves and linked_plots are hinted as Sequence instead of as List
Added support:
Support for Numpy 2.0
3.3.0 (2023-02-27)
Raise ImportError instead of general Exception
3.2.6 (2022-10-13)
Added link to notes on use-case: DAQ
3.2.5 (2022-10-13)
Minor edit: Using explicit arguments x and y to set the curve data and set the flag skipFiniteCheck=True. Both save (marginal) CPU time.
3.2.4 (2022-10-12)
Bug fix: Snapshot creation checks if internal buffer is of type RingBuffer and casts to numpy.ndarray. This resolves an intermittent error where the isfinite boolean return array was operating as mask on the RingBuffer, which fails. The boolean return array now always operates on numpy.ndarray.
Fix for external bug in paintGL of pyqtgraphgraphicsItemsPlotCurveItem.py: Added explicit check to ensure that the curve is only drawn when it has more than 1 point.
Added benchmark running python=3.10 and pyqtgraph==0.13.1
3.2.3 (2022-10-11)
Fixed bug when using PyQt6: QMessageBox.Yes –> QMessageBox.StandardButton.Yes
3.2.2 (2022-09-18)
Updated discussion on benchmarks
The batch file for auto-creation of the conda environments found in the benchmark folder now uses the conda-forge channel.
3.2.1 (2022-09-17)
Neater mechanism to support both PyQt and PySide
Added benchmarks
Improved demos
3.2.0 (2022-09-13)
Added support for PyQt5, PyQt6, PySide2 and PySide6 as suggested via a pull request by Mathijs van Gorcum (https://github.com/mvgorcum).
3.1.0 (2021-05-10)
Removed redundant argument capacity from init PlotCurve(). It is not using a ringbuffer and, hence, does not need a capacity.
3.0.1 (2020-08-07)
Bug-fixes:
The use of typing.TypedDict broke support under Python 3.6 and 3.7. Fixed by conditional import typing_extensions.
Curve plotting was broken when setClipToView(True) and the curve data extended past the viewbox limits, when not using OpenGL. The cause was my incorrect calculation of connect. Fixed by commenting out connect again. Curves will now show continuously (linear interpolation) whenever a NaN is encountered, instead of as correctly fragmented. That’s acceptable.
3.0.0 (2020-08-07)
Renamed parameter LegendSelect.curves to LegendSelect.linked_curves
Changed base of class LegendSelect() from QWidget to QObject
Added class PlotManager()
2.0.1 (2020-08-03)
Workaround: PyQt5 >= 5.12.3 causes a bug in PyQtGraph where a curve won’t render if it contains NaNs (but only in the case when OpenGL is disabled). The curve will now be displayed correctly, i.e., fragmented whenever a NaN is encountered. When OpenGL is enabled, linear interpolation will occur at the gaps as per pyqtgraph.plotCurveItem.paintGL().
2.0.0 (2020-08-02)
Method names are now conform the PyQtGraph naming style. I.e. setData() vs. set_data(), etc.
The default values of PyQtGraph are no longer being overwritten.
Added class LegendSelect
1.0.0 (2020-07-30)
First release on PyPI
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
File details
Details for the file dvg_pyqtgraph_threadsafe-3.4.0.tar.gz
.
File metadata
- Download URL: dvg_pyqtgraph_threadsafe-3.4.0.tar.gz
- Upload date:
- Size: 106.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1cbd7aceabe0b85c86921e9ed6e6a03a782aa5e7301c7faf896b486df52c30f7 |
|
MD5 | a65435eecd8e109c95c6c4396c8ba12d |
|
BLAKE2b-256 | 590c3589bcab501bf780903f918925dbc792b0649f92028e75d76ce28c46d713 |
File details
Details for the file dvg_pyqtgraph_threadsafe-3.4.0-py3-none-any.whl
.
File metadata
- Download URL: dvg_pyqtgraph_threadsafe-3.4.0-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 43e7d531b46a2abf68c7ca782fe679f3a7004ea0e6d25155b5af004f70f1a3b1 |
|
MD5 | 4703890796da8453af125b3c8c421093 |
|
BLAKE2b-256 | 000daee2d2b7ba08d3ff934d8cf7b3865a9d1e536ee212a7d53e7a2271c25662 |