2.3. QeTrend - Time-Series Trend Widget
2.3.1. Overview
QeTrend is a time-series trend widget built on the QwtPlot library. It extends
QePlotBase to provide date-time X-axis scaling and point-by-point data
appending. Unlike QePlot which accepts bulk 1D arrays, QeTrend is designed for
streaming scenarios where individual (value, timestamp) pairs are appended over
time. The X axis uses a QwtDateScaleDraw with UTC timestamps, and each
curve maintains a bounded queue of configurable size with automatic oldest-sample
eviction.
The widget inherits the full Qwt plotting infrastructure from QePlotBase including zoom, pan, toolbar, line/scatter toggling, Y-axis scale selection, and PDF export.
QeTrend widget
2.3.1.1. Constructor
The constructor signature is
QeTrend(parent: QWidget = None)
Parameters:
parent (
QWidget, optional) – Parent widget.
Example:
# Any Qt Widget needs an Application running
from PySide6.QtWidgets import QApplication
app = QApplication([])
from cut.wdglib.widgets import QeTrend
trend = QeTrend()
trend.show()
2.3.1.2. Inheritance Hierarchy
QeTrend inherits from QePlotBase which encapsulates the shared Qwt plotting
infrastructure:
2.3.2. Methods
2.3.2.1. Data Loading
- cut.wdglib.widgets.CreateOrAppendToTrend(value: float, timestamp: float, curveName: str = '') None
Append a single (value, timestamp) data point to a named curve. If the curve name is empty, one is auto-generated as
"Curve N"based on the current curve count. If a curve with the given name already exists, the new point is appended to the existing curve. If it does not exist, a new curve is created.Only the
doubleoverload is exposed in the Python bindings. Integer or other numeric types passed from Python are automatically converted to float by Python before being passed to this method.The X axis displays human-readable date-time labels derived from the UTC epoch timestamp. If appending a point causes the curve to exceed the current queue size, the oldest samples are automatically dropped.
- Parameters:
value – The sample value (plotted on the Y axis).
timestamp – POSIX UTC epoch timestamp (seconds since Jan 1, 1970).
curveName – Optional curve identifier. Auto-generated if empty.
Example:
import time from cut.wdglib.widgets import QeTrend trend = QeTrend() now = time.time() # Plot points on a curve named "sine" for i in range(100): value = math.sin(i * 0.1) trend.CreateOrAppendToTrend(value, now + i, "sine")
- cut.wdglib.widgets.CreateOrAppendToMemberVectors(value: float, timestamp: float, curveName: str = '') None
Exposed protected method that performs the same core logic as
CreateOrAppendToTrend: appends a (timestamp, value) pair to the internal data vectors for a named curve, trims by queue size, and replots. This method is not intended for direct use; it is the internal implementation that the typed C++ overloads delegate to.- Parameters:
value – The sample value.
timestamp – POSIX UTC epoch timestamp.
curveName – Optional curve identifier.
- cut.wdglib.widgets.ClearCurves() None
Remove all curves from the plot, clear the internal curve map, and release the timestamp/value data vectors for each curve. This overrides the base
QePlotBase::ClearCurves()to ensure the trend-specific data structures are also cleaned up.
2.3.2.2. Queue Management
- cut.wdglib.widgets.GetQueueSize() int
Return the maximum number of points kept per curve. When a new point is appended and this limit is exceeded, the oldest point is dropped.
- Returns:
Current queue size limit (default:
1000).
- cut.wdglib.widgets.SetQueueSize(newQueueSize: int) None
Set the maximum number of points per curve. The value must be >= 1. If the new size is smaller than the current data size for any curve, the oldest samples are trimmed immediately. Emits the
QueueSizeChangedsignal.- Parameters:
newQueueSize – New queue size limit.
- cut.wdglib.widgets.ResetQueueSize() None
Reset the queue size to the default value of
1000.
2.3.2.3. Toolbar Management
- cut.wdglib.widgets.ToggleToolbar() None
Toggle the visibility of the plot toolbar.
- cut.wdglib.widgets.SetMainWindowForToolbar(window: PySide6.QtWidgets.QMainWindow) None
Assign the owning QMainWindow so the toolbar can be docked into it.
- Parameters:
window – The QMainWindow that will host the plot toolbar.
2.3.2.4. Zoom Controls
- cut.wdglib.widgets.on_actionQePlotZoom_In_triggered() None
Zoom in on the plot canvas by a factor of 0.75.
- cut.wdglib.widgets.on_actionQePlotZoom_Out_triggered() None
Zoom out on the plot canvas by a factor of 1/0.75.
- cut.wdglib.widgets.on_actionQePlotZoom_Reset_triggered() None
Reset zoom level and re-enable auto-scaling on both axes.
2.3.2.5. Plot Style
- cut.wdglib.widgets.on_actionLine_Plot_triggered(checked: bool) None
Toggle line plot mode.
Trueconnects points with lines;Falseswitches to scatter mode.
- cut.wdglib.widgets.on_actionScatter_Plot_triggered(checked: bool) None
Toggle scatter plot mode.
Trueshows point markers only;Falseswitches to line mode.
2.3.2.6. Y-Axis Scale
- cut.wdglib.widgets.on_actionYAxis_Linear_triggered(checked: bool) None
Switch the Y-axis to linear scale.
- cut.wdglib.widgets.on_actionYAxis_Log_triggered(checked: bool) None
Switch the Y-axis to logarithmic scale. Forces scatter mode and disables the line plot toggle.
- cut.wdglib.widgets.on_actionYAxis_Square_Root_triggered(checked: bool) None
Stub for square-root Y-axis scale. Not yet implemented.
2.3.2.7. PDF Export
- cut.wdglib.widgets.on_actionExport_triggered() None
Export the current plot to a PDF file in the user’s home directory with a UTC timestamp in the filename.
2.3.3. Protected Event Handlers
These methods are called by Qt during widget lifecycle events.
- cut.wdglib.widgets.showEvent(event: PySide6.QtGui.QShowEvent) None
Called when the widget becomes visible. Attaches the toolbar to the owning QMainWindow.
- cut.wdglib.widgets.hideEvent(event: PySide6.QtGui.QHideEvent) None
Called when the widget is hidden. Detaches the toolbar from the owning QMainWindow.
2.3.4. Exposed Member Variables
m_color_list (list[QColor]) – Read-only palette of 7 colors assigned to curves in rotation. Inherited from QePlotBase.
2.3.5. Signals
QeTrend defines one custom signal beyond the standard Qt signals inherited from QWidget and QObject:
- cut.wdglib.widgets.QueueSizeChanged(value: int)
Emitted when the queue size is changed via
SetQueueSize()orResetQueueSize().- Parameters:
value – The new queue size (maximum points per curve).
Example:
trend.QueueSizeChanged.connect(lambda v: print(f"Queue size: {v}")) trend.SetQueueSize(500) # prints "Queue size: 500"
The standard Qt signals are also available:
customContextMenuRequested(pos: QPoint)
destroyed(obj: object = None)
objectNameChanged(name: str)
windowTitleChanged(title: str)
windowIconChanged(icon: QIcon)
windowIconTextChanged(text: str)
2.3.6. QeTypes Enum
The QeTypes enum is importable from cut.common.pyb. While
CreateOrAppendToTrend accepts only double values in Python,
the internal C++ overloads for other types use this enum for type
identification.
- QeTypes.Int8
- QeTypes.Int16
- QeTypes.Int32
- QeTypes.Int64
- QeTypes.UInt8
- QeTypes.UInt16
- QeTypes.UInt32
- QeTypes.UInt64
- QeTypes.Float
- QeTypes.Double
- QeTypes.String
- QeTypes.Boolean
- QeTypes.NotSet
2.3.7. Example Usage
Basic time-series plotting:
import time, math
from cut.wdglib.widgets import QeTrend
from PySide6.QtWidgets import QApplication
app = QApplication([])
trend = QeTrend()
now = time.time()
for i in range(200):
value = math.sin(i * 0.05) * math.exp(-i / 200.0)
trend.CreateOrAppendToTrend(value, now + i * 0.1, "damped_sine")
trend.ToggleToolbar()
trend.show()
app.exec()
Multiple curves:
import time, math
from cut.wdglib.widgets import QeTrend
trend = QeTrend()
now = time.time()
for i in range(100):
t = now + i * 0.1
trend.CreateOrAppendToTrend(math.sin(i * 0.1), t, "sine")
trend.CreateOrAppendToTrend(math.cos(i * 0.1), t, "cosine")
# Configure display
trend.on_actionLine_Plot_triggered(True)
trend.QueueSizeChanged.connect(lambda v: print(f"Queue size: {v}"))
Queue size management:
from cut.wdglib.widgets import QeTrend
trend = QeTrend()
print(f"Default queue size: {trend.GetQueueSize()}") # 1000
trend.SetQueueSize(500)
# Now each curve will hold at most 500 points
trend.ResetQueueSize()
# Back to 1000
Stream simulation:
import time, math
from cut.wdglib.widgets import QeTrend
trend = QeTrend()
trend.SetQueueSize(100) # Keep only last 100 points
for i in range(500):
trend.CreateOrAppendToTrend(
value=math.sin(i * 0.2) + (i * 0.001),
timestamp=time.time() + i * 0.01,
curveName="sensor_1"
)
# After 500 appends, only the last 100 points are retained
2.3.8. Notes
Only the
doubleoverload ofCreateOrAppendToTrendis exposed in Python. The C++ header declares 11 overloads (one for each numeric type), but all exceptdoubleare removed from the Python bindings. The comment in the typesystem XML explains: “Internally, QwtPlot accepts only doubles so a conversion would have been done later.” Integer values passed from Python are automatically promoted to float by Python.The X axis uses UTC epoch timestamps with
QwtDateScaleDraw, displaying human-readable date labels at millisecond/second/minute/hour granularity.No
setNumpyNdArray()convenience method is provided for QeTrend, unlike QePlot, QeMatrixView, and QeVectorView. This is intentional: the trending API uses discrete point-by-point appending with timestamps rather than bulk array loading.When
SetQueueSize(n)is called withnsmaller than the current data size, the oldest samples are immediately dropped from all curves.Curves are auto-named as
"Curve 0","Curve 1", etc. if no name is provided. Providing the same name on subsequent calls appends to the existing curve rather than creating a new one.The widget does not support multi-curve bulk plotting from Python. Each call to
CreateOrAppendToTrendappends exactly one data point.The toolbar is hidden by default. Call
ToggleToolbar()to show it.PDF export writes to
~/qeplot-<timestamp>.pdf. There is no way to override the output path from Python.Mouse interaction is built-in: left-click drag for panning, mouse wheel for zooming, with coordinate tracking shown as a tracker tooltip.
The Y-axis logarithmic scale forces scatter mode and disables line plot.
The square-root Y-axis scale (
on_actionYAxis_Square_Root_triggered) is a stub with no implementation.