Skip to content

Changelog

All notable changes to QAccelPlot are documented in this file.

The format is based on Keep a Changelog.

[Unreleased]

[0.5.0] — 2026-11-01

Added

  • Heatmaps via HeatmapSeries: a uniform grid of values colored through a Colormap, with a ColorBar key, a Heatmap example, and cell inspection through PlotInspector and inspection.dataPointAtPosition(). Heatmaps draw on logarithmic axes, and xSpacing/ySpacing: HeatmapSeries.Log spaces cells evenly in log10.
  • valueText inspection role with the value of a heatmap cell or a colored PointCloud point. The default InspectionTooltip row shows it.
  • Legend entries described in C++: PlotSeries::legendEntry() returns a LegendEntry, and LegendModel lists the entries of the visible series that have one, such as Plot.legendModel.
  • A HeatmapSeries tab in the showcases/performance example, streaming a scrolling spectrogram of up to 100M cells.
  • Colormapped bars: BarSeries.colormap colors each bar by its value or, with colorSource: BarSeries.Position, by its position or bin. The Heatmap example keys its interference pattern with a histogram of the cells in view.
  • Image export with PlotExporter: save a plot as PNG, JPEG, or another raster format, copy it to the clipboard, or capture a QImage, at a chosen scale. Includes an Export example.
  • Error bars via ErrorBarSeries: vertical or horizontal capped lines, set as bounds or as symmetric or asymmetric errors with setErrorData(), and animated by MorphTransition and DrawTransition. Includes an Error Bars example.
  • PlotSeries.hoverEnabled turns hover off for one series and leaves it to the series beneath. hovered moved to PlotSeries, so PointCloud, BarSeries, RectangleSeries, and ErrorBarSeries report it too.
  • PlotSeries.count on every series, including LineCurve (points) and HeatmapSeries (cells, columns × rows).
  • antialiasing: true smooths RectangleSeries and BarSeries edges. It is off by default.
  • Step lines via LineCurve.stepMode (Before, After, or Center): the fill, dash pattern, hover, and interpolated inspection follow the steps. Includes a Step Lines example.
  • PlotView.rectangleZoom.visible: false hides the drawn zoom rectangle, so you can draw selectionRect yourself.
  • PlotInspector.cursorPixelX and cursorPixelY place the cursor in plot-local pixels; it stays on those pixels when the axes pan or zoom.
  • Named categories on BarSeries and RectangleSeries: categories lists Category objects with a value, name, and color, a data point's category is a value or, in QML, a name, and the legend shows one row per category through PlotSeries::legendEntries().
  • A Vibration Monitoring showcase: eight accelerometer channels streamed live, 2M points replaced every frame, with spectrum, spectrogram, and RMS panels. Examples can record deterministic frames with --record, and scripts/frames-to-gif.py turns them into a GIF.

Changed

  • The C++ plot item class QAccelPlot::QAccelPlot is now QAccelPlot::PlotView, its QML name, in <QAccelPlot/PlotView.hpp>. QML is unchanged.
  • Grid.lineWidth is now gridLineWidth, matching subGridLineWidth. In C++, use gridLineWidth(), setGridLineWidth(), and gridLineWidthChanged().
  • Marker shapes are a standalone MarkerShape enum instead of a PlotSeries enum. Replace LineCurve.Diamond or PointCloud.Circle with MarkerShape.Diamond or MarkerShape.Circle in QML, and PlotSeries::MarkerShape with MarkerShape (<QAccelPlot/series/MarkerShape.hpp>) in C++. Values are unchanged.
  • PlotMouseEvent.button is Qt.NoButton for a move instead of the held buttons cast into one value; the new buttons holds them. reset() is no longer public.
  • Colormap.norm is now logScale: bool, like Axis.logScale. Replace norm: Colormap.Log with logScale: true in QML, and setNorm(Colormap::Normalization::Log) with setLogScale(true) in C++. The Colormap::Normalization enum is removed.
  • Renamed PlotInspector.position to crosshairPosition, and positionChanged() to crosshairPositionChanged().
  • Inspection data points place a point as x, y (data units) and pixelX, pixelY (series-local pixels). Replace pixelPosition.x with pixelX, and the inspection row role pixelPosition (plot-local) with pixelX and pixelY. In C++, InspectionDataPoint::position and x()/y() are now the x and y members.
  • Renamed SelectionTool.rectangleVisible to visible and pixelRect to selectionRect, matching PlotView.rectangleZoom. Signals and C++ accessors follow: visibleChanged(), isVisible(), setVisible(), selectionRect(), selectionRectChanged().
  • BarSeries and RectangleSeries take categories instead of categoryColors: replace categoryColors: [a, b] with categories: [Category { value: 0; color: a }, Category { value: 1; color: b }]. setCategories() for the data points is now setDataPointCategories(). A QML category that is neither a whole number nor a category name is ignored with a warning.
  • Series use the antialiasing property inherited from Item. LineCurve.antialiasingEnabled, PointCloud.antialiasingEnabled, and LegendEntry.antialiasingEnabled are now antialiasing. BandSeries edge lines and ErrorBarSeries follow it too.
  • Outlines use one border grouped property with color and width. PlotView.rectangleZoom.borderColor, SelectionTool.borderColor, and ColorBar.borderColor/borderWidth are now border.color/border.width. The rectangle zoom and selection outlines can now be wider than 1 px. In C++, PlotBorder and RectangleBorder are now Border (<QAccelPlot/Border.hpp>).
  • ColorBar.series takes any ColormappedSeries, the new base of PointCloud, HeatmapSeries, and BarSeries. In C++, ColorBar::series() returns a ColormappedSeries*.
  • Legend takes a model instead of series. Hidden series have no entry, and unnamed series are listed as "Series N".
  • inspection.status is Ready for bar, rectangle, band, and heatmap series instead of Unsupported. Queries that do not apply to them still return Unsupported.
  • A LineCurve with hover off no longer scans its points on every data update. Streaming eight 512K-point curves takes about a quarter of the UI-thread time.
  • LineCurve markers read their positions from the GPU data texture, so data updates no longer rebuild a vertex buffer per marker.
  • When a LineCurve point count grows, only the added points' vertices are written.
  • Data transitions run on Qt's animation clock, like QML animations, so an installed QAnimationDriver can step them frame by frame. A duration of 0 ends at the next frame.
  • The showcases/performance example presents without vsync, so the refresh rate no longer caps display FPS.

Removed

  • SeriesInspection.supported. A query that does not apply to a series returns Inspection.Unsupported.
  • SeriesInspection.maximumPageSize. indices() caps limit at 4096 and each page reports the size used in limit.
  • PlotView.pointerPosition, pointerInside, and pointerChanged(). Use PlotInspector.cursorPixelX, cursorPixelY, and active, or a HoverHandler.
  • PointCloud.hasValues. valueAt() returns NaN when no values are stored. countChanged() now fires only when the number of points changes.
  • LineCurve::setDataFWithCache() and the renderers' buildVertexCache(). Use setDataF() or postData(); the curve builds its own vertex cache.
  • The showcases/pulsar example.
  • The CI benchmark workflow: its timings on shared runners varied more than its alert threshold. A unit test now counts scene graph rebuilds and data uploads per frame instead.
  • The benchmarks/ directory and the QACCELPLOT_BUILD_BENCHMARKS option. Measure frame rates with the Performance Lab.
  • RectVertexCache from the public headers. It was an internal helper of BarSeries and RectangleSeries.
  • effects/GradientCoordinateUtils.hpp and effects/GradientUtils.hpp from the public headers. Their helpers were internal to the gradient effects, Colormap, and LineCurve.

Fixed

  • LineCurve, BarSeries, RectangleSeries, and BandSeries no longer hover records beyond their GPU capacity, which are not drawn.
  • Changing PointCloud.hoverRadius or ErrorBarSeries.hoverRadius updates hoveredIndex without waiting for the mouse to move.
  • Colormap.stops reads bound GradientStops after their bindings are evaluated, and follows later changes to stops declared in the list.
  • Panning and zooming no longer re-upload every series' vertex data each frame: the grid updates its scene graph nodes in place.
  • Incremental builds recompile a shader when a .glsl file it includes changes. Stale shaders could fail to link on OpenGL and draw no curves.

[0.4.0] — 2026-10-16

Added

  • Rectangle zoom via PlotView.rectangleZoom and zoomToRect(), with theme colors and a Point cloud example.
  • Data inspection via PlotInspector and SelectionTool: a crosshair, per-series markers, and a tooltip at the cursor, region selection with statistics, theme colors, and a Data inspection example.
  • Data point queries on every series via PlotSeries.inspection: the nearest data point, its neighbors, statistics of a region, and the indices inside it.
  • PlotView.overlay for items drawn above the series, and the pointer position via pointerPosition and pointerInside.
  • Axis.formatValue(), which formats a value at the precision of the current zoom.
  • RectangleSeries: rectangleAt(), rectangleIndexAt(), clearData(), setData(std::vector<double>&&, int), and postData().
  • RectangleSeries spans: infinite or omitted edges reach the plot edge.
  • RectangleSeries.minimumWidth and minimumHeight, 1 px by default.
  • RectangleSeries categories: category, categoryColors, and setCategories().
  • RectangleSeries.border.width and border.color.
  • RectangleSeries.hoverColor.
  • RectangleSeries: setDataF() and float postData() overloads.
  • SpatialGrid::buildF().
  • RectVertexCache.
  • BarSeries: orientation, barWidth, barOffset, baselineValue, barAt(), and barIndexAt().
  • BarSeries ranged bars with their own from and to, via setData() and setRangedData().
  • BarSeries.transition: MorphTransition and DrawTransition animate bar updates.
  • PointCloud.transition: MorphTransition and DrawTransition animate point updates.
  • LineCurve.hoverRadius.
  • The plot_types/bar_chart example.
  • The plot_types/state_timeline example.
  • BandSeries with edges, valueAt(), and hovered.
  • The plot_types/bands example.
  • Histograms via Histogram: equal or uneven bins, counts or density, as data for a BarSeries, with a Histogram example.
  • Axis.autoRescale, which fits the viewport to the data range on every data update.
  • PlotSeries::DataBounds overloads of setData() and setDataF(), which take the data extents instead of scanning for them.
  • PlotSeries::xDataRange() and yDataRange() are public.
  • ColorBar.interactive: dragging pans the colormap range, the wheel zooms it, and a double-click or rescaleToData() resolves it from the data again. hovered reports the cursor over it.

Changed

  • PlotSeries::setData(), setDataF(), and postData() are no longer virtual: C++ subclasses pass their data point layout to the PlotSeries constructor.
  • Renamed the C++ and QML RectangleList type to RectangleSeries. Include <QAccelPlot/series/RectangleSeries.hpp> in C++ code.
  • GradientStroke::payload() and GradientFill::payload() return a reference to a snapshot that the effect updates on the GUI thread. The new LineCurveEffect::refresh() re-reads inputs that change without a notification.
  • DataTransition::start() and advance() take a DataTransition::Run that holds one element's animation state.
  • DataTransition::interpolate() takes DataTransition::Dataset arguments, and start() a stride for points of more than two values.
  • DrawTransition starts from one point instead of two.
  • Moved RectangleSeries.hpp to QAccelPlot/series/.
  • Replaced RectangleSeries::setData(const float*, int) with setDataF(const float*, int).
  • PointCloud uses half the GPU vertex memory per point.
  • PointCloud and RectangleSeries hover scans live data instead of rebuilding its spatial index after every data update.
  • The showcases/performance example has LineCurve, PointCloud, RectangleSeries, and BarSeries tabs, each with options for series count, ingestion API, hover, and rendering.
  • Axis::rescaleToData() emits rangeChanged() once instead of once per bound.
  • Data ranges are computed on demand. Data setters no longer scan for the range; a series scans when Axis.dataMin / dataMax, rescaleToData(), an axis with autoRescale, or a DataRange gradient reads it.
  • Axis.dataMinChanged() and dataMaxChanged() also announce a data update whose range has not been computed yet.
  • Renamed LineCurve::setDataFNoRangeWithCache() to setDataFWithCache().
  • Renamed Axis::updateDataRange() to setDataRange().
  • Axis.orientation, ColorBar.orientation, and the direction of GradientFill and GradientStroke take Qt.Horizontal / Qt.Vertical. This replaces Axis.Orientation, ColorBar.Orientation, and GradientDirection.
  • Renamed GradientFill and GradientStroke properties: gradientValueMin → valueMin, gradientValueMax → valueMax, gradientValueMinSource → valueMinSource, and gradientValueMaxSource → valueMaxSource.
  • Renamed Axis.axisTitlePadding to labelPadding and Axis.axisLinePadding to baselinePadding.
  • Axis.labelPadding, Axis.baselinePadding, and zoomScaleFactor of Axis and ColorBar are qreal.
  • button is a Qt::MouseButton and modifiers a Qt::KeyboardModifiers on PlotMouseEvent, SelectionTool, and PlotView.rectangleZoom, instead of int.
  • Renamed nearly_equal() in MathUtils.hpp to nearlyEqual().
  • The QML module version follows the project version, 0.4 in this release, instead of 1.0. Replace import QAccelPlot 1.0 with import QAccelPlot.
  • PlotView::rescaleAllAxes() is public instead of protected.

Removed

  • The setDataNoRange() and setDataFNoRange() setters. Use setData() and setDataF(), which no longer scan. To keep a range the application maintains, pass it as PlotSeries::DataBounds instead of setting Axis.dataMin / dataMax.
  • PlotSeries::xDataRangeChanged() and yDataRangeChanged(). Read xDataRange() and yDataRange(), or connect to Axis.dataMinChanged() / dataMaxChanged().

Fixed

  • TextTickLabelFormatter returns an empty label for non-finite or out-of-range tick values without an integer conversion failure.
  • Changing an inward or outward tick length now notifies bindings to the total tick or subtick length.
  • An axis already assigned to a plot slot cannot also occupy another axis slot or appear in extraAxes.
  • Plot with legend: null no longer logs a TypeError.
  • On a logarithmic axis, RectangleSeries edges at or below zero no longer widen the data range, so autoscaling no longer reaches down to 1e-10.
  • Rescaling a logarithmic axis with an entirely non-positive data range keeps its viewport positive and usable.
  • Zooming or panning an axis stops at the limits of a double. Zooming a logarithmic axis far out no longer leaves a NaN viewport.
  • Axes and color ranges preserve distinct values below machine epsilon, so small data spans map across the plot instead of collapsing to one pixel.
  • LineCurve with both a line and markers is hovered along the line, not only on markers.
  • Hovering a RectangleSeries or BarSeries whose records share one coordinate far from zero, such as a zero-width rectangle at a nanosecond timestamp, no longer crashes.
  • GradientFill on dense data reaches the curve's peaks and troughs.
  • Gradient effects with a DataRange bound use the curve's own data extent, not the whole axis range.
  • LineCurve and PointCloud keep double precision when the viewport is far from the first data point, e.g. at the end of a long timestamp series.
  • Hovering a PointCloud whose points lie on a long horizontal line no longer tests every point.
  • PointCloud no longer hovers points beyond the GPU texture capacity, which are not drawn.
  • Colormap now drops destroyed stops and updates its ramp when a stop changes.
  • Colormap ignores null entries in stops instead of crashing.
  • A series whose log-scale axis was destroyed refreshes its data ranges when bound to a linear axis.
  • RectangleSeries and BarSeries keep double precision when the viewport is far from the first record.
  • LineCurve transitions now advance on the GUI thread, so DataTransition.running changes, and the QML handlers and bindings that react to them, no longer run on the scene graph render thread.
  • A series constructed in C++ with a PlotView as its parent, such as new LineCurve(plot), is now listed in PlotView.series and follows the plot area when the plot is resized. Previously it kept the first plot area it saw, which it adopted from the scene graph render thread.
  • The showcases/performance and showcases/pulsar examples no longer hang on exit.
  • LineCurve no longer reads the QML Gradient of a GradientStroke or GradientFill from the scene graph render thread on every frame. The effect now reads it on the GUI thread when it changes and once per frame, so stop changes that Gradient does not signal still show up.
  • Curves sharing one DataTransition animate to their own data.
  • Replacing, clearing, cancelling, or destroying a running LineCurve transition, or calling appendData() during it, shows the new data instead of freezing the animation.
  • A LineCurve transition that starts from float data in NanGapMode.Connect no longer crashes when the curve is hovered.
  • RectangleSeries no longer blocks hover for series underneath it.
  • RectangleSeries and BarSeries skip drawing on the software backend, like the other series, instead of corrupting memory when their data changes.
  • Attaching an empty series no longer resets an axis's dataMin and dataMax to 0 and 1.
  • RectangleSeries and PointCloud render up to about 16M rectangles or 22M points (data texture rows are 8192 texels wide).
  • LineCurve, RectangleSeries, and BarSeries draw only the records their GPU buffers hold and warn about the rest, instead of overflowing the vertex buffer. These series, BandSeries, and PointCloud warn each time their data outgrows the capacity, not once per application.
  • On Qt 6.2, only the topmost series under the cursor is hovered.
  • A destroyed series leaves PlotView.series, and a destroyed PlotView releases its children, before their own members are gone, so handlers of seriesChanged no longer see a half-destroyed plot or series.

[0.3.0] — 2026-09-25

Added

  • Marker shapes TriangleLeft, TriangleRight, XCross, HLine, VLine, Star, Asterisk, Hexagon, and Pentagon, and a Pixel marker that draws each sample as a single pixel for very dense scatter plots.
  • Hollow markers: set marker.filled to false to outline filled shapes with marker.strokeWidth pixels. Legend symbols follow the series.
  • The styling/markers example shows every shape. Click a shape to draw a scatter plot with it, and adjust marker size, outline, and opacity.
  • The plot_types/parametric_curves example draws curves whose x values do not increase: a spiral, a Lissajous figure, a spirograph, and a Van der Pol phase portrait.
  • The plot_types/point_cloud example draws a value-colored cloud with a color bar.
  • LineCurve::setData(std::vector<double>&&, int) moves an interleaved double buffer into the curve, keeping double precision for large coordinates such as Unix-epoch timestamps without re-interleaving.
  • LineCurve::postData(std::vector<double>&&, int) hands off an interleaved double buffer from a worker thread, like the existing float postData().
  • PointCloud series for large unconnected scatter data. Its markers use the same marker grouped property as LineCurve.
  • Colormap, mapping data values to colors through a built-in ramp (Viridis, Plasma, Inferno, Magma, Grayscale, Rainbow) or custom stops, with optional bounds, linear or logarithmic normalization, and a reversed flag. GradientFill.colormap and GradientStroke.colormap take a colormap as an alternative to gradient, which it overrides when both are set. PointCloud.colormap colors points by their per-point values.
  • ColorBar, a continuous key for a PointCloud colormap. It draws the ramp with ticks for the series' resolved value range, follows Linear and Log normalization, and redraws when the colormap or range changes. Vertical and horizontal orientations; ticks are configured through ticker, as on Axis.

Changed

  • Public headers are now included with a QAccelPlot/ prefix, for example #include <QAccelPlot/series/LineCurve.hpp>, both when QAccelPlot is embedded with add_subdirectory or FetchContent and when it is installed. The library sources moved to QAccelPlot/src/QAccelPlot/. Replace unprefixed includes such as "series/LineCurve.hpp".
  • LineCurve.markerShape and markerSize moved to marker.shape and marker.size.
  • Examples are grouped by category under examples/: plot_types/, styling/, axes/, data/, interaction/, and showcases/, with quickstart/ at the top. Renamed examples: axis_formats → axes/tick_formats, custom_axis → axes/multiple_axes, interactive_tools → interaction/measurement_tools, performance_showcase → showcases/performance, and pulsar_showcase → showcases/pulsar. Their executables are renamed to match, for example QAccelPlotExampleTickFormats.
  • The styling and transitions example is split into single-topic examples: styling/line_styles, styling/markers, styling/gradients, styling/transitions, styling/theming (dark and light palettes), and data/missing_data (invalid samples and gaps).

Removed

  • LogTickLabelFormatter. The default NumericTickLabelFormatter now labels logarithmic axes with the same superscript powers of ten.

Fixed

  • The Qt Quick opacity property, set on a series or inherited from a parent item, now applies to LineCurve lines, markers, GradientStroke, and GradientFill, and to PointCloud and RectangleList. Previously it had no effect. Each fragment blends on its own, so overlapping translucent markers build up density.
  • Numeric tick labels no longer show a spurious trailing zero. Labels now use exactly the decimal places needed to write the tick step, so steps of 1 and 2 read 0, 1, 2 instead of 0.0, 1.0, 2.0, and steps of 0.1 and 0.2 read 0.1, 0.2 instead of 0.10, 0.20. All labels on a linear axis keep the same number of decimals, for example 0.0, 0.5, 1.0, 1.5, 2.0.
  • Logarithmic axes now label decades as superscript powers of ten (10⁻², 10⁻¹, 10⁰, 10¹, 10²) by default, instead of 0.010, 0.10, 1.0, 10, 100. Custom formatters can override the new TickLabelFormatter::doFormatLogTick(); tickLabel callbacks are unchanged.
  • LineCurve now renders its marker for a single-point dataset when both lines and markers are enabled.
  • Rectangle hover detection now preserves double precision for large coordinates, including Unix-epoch timestamps, so nearby rectangles remain distinguishable.
  • RectangleList now refreshes its render coordinates when either axis switches between linear and logarithmic scales, keeping rectangles positioned correctly without requiring new data.
  • Overlapping rectangles no longer cause quadratic memory growth in the hover lookup index, preventing excessive memory use and crashes with large datasets.
  • Removing, reparenting, or destroying a plot series no longer leaves it registered with its former plot, preventing later updates from accessing a dangling series pointer.
  • LineCurve no longer keeps a dangling transition pointer when an externally owned data transition is destroyed; the property is cleared and its change is reported.
  • Canceling, replacing, or destroying a LineCurve transition before its first rendered frame no longer leaves the point count inconsistent with the available data buffers, preventing out-of-bounds rendering access.
  • Toggling a LineCurve gradient stroke no longer double-deletes its scene graph node and crashes; the renderer now preserves the node while replacing its material.
  • Setting a linear axis ticker's tickCount to zero or below now disables its grid generation instead of potentially exhausting memory, and hiding both the main grid and subgrid clears existing geometry.
  • Antialiased lines and markers no longer lose coverage inside their nominal size. The antialiasingFeather ramp is now centered on the edge, so 1 px lines stay continuous regardless of pixel alignment, the 1 px legend symbol is visible, and thicker lines render at their full width. Lines thinner than 1 px draw 1 px wide with proportionally reduced alpha.
  • Diamond, TriangleUp, and TriangleDown markers are no longer clipped flat at their tips, and their antialiased edges are equally soft on every side. They keep their previous width and height.
  • GradientStroke and GradientFill now keep a Fixed gradient value bound when the other bound uses DataRange. Previously both bounds were taken from the data range.
  • GradientStroke and GradientFill now redraw when a stop of their gradient changes color or position at runtime.

[0.2.0] — 2026-09-16

Added

  • Per-axis layoutSize control for explicitly reserving horizontal-axis height or vertical-axis width.
  • Automatic side assignment for the four named plot axes: xAxis uses the bottom, x2Axis the top, yAxis the left, and y2Axis the right.
  • Explicit invalid-sample contract for LineCurve: NaN, ±Inf, and non-positive values on logarithmic axes break the line, gradient fill, and hover hit testing consistently on every graphics backend, never draw markers, and are excluded from auto-ranging per dimension.
  • LineCurve.gaps grouped property. gaps.nanMode selects NanGapMode.Break (default) or NanGapMode.Connect, which joins the valid samples on either side of a gap.
  • A "Gaps" page in the styling and transitions example.

Changed

  • Values at or below zero on a logarithmic axis now render as gaps instead of being clamped to a steep drop toward the bottom of the plot.
  • MorphTransition no longer interpolates from or to non-finite coordinates: new gaps appear immediately and samples leaving a gap jump to their target.
  • Renamed RectangleList::setRawData() to setData(), matching the naming of the LineCurve data-setting APIs.
  • Default plot, axis, grid, series, and legend colors now come from the built-in dark palette instead of generic Qt colors. The Colors palette is defined once in C++ and shared with QML, where its usage is unchanged.

Fixed

  • Legend line and marker samples now use the curve renderers, keeping marker shapes and dash patterns consistent across graphics backends and display scales.
  • Preserved double precision in LineCurve::setData() for modern Unix-epoch timestamps and large coordinates while keeping the F ingestion APIs float-based.
  • Reassigning a LineCurve's effects list no longer deletes the effect objects, and effects destroyed elsewhere are removed from the list instead of leaving dangling entries.
  • A running LineCurve transition no longer overwrites data pushed through appendData() or through a data-setting API called after disabling the transition mid-animation: any in-flight transition is now cancelled before the new data is applied directly.
  • Major tick marks now honor fractional tickWidth values (e.g. 1.5) instead of truncating to an integer pixel width.
  • LineCurve no longer leaks the default SolidLine it creates for its lineStyle: the default is owned by the curve and released when the curve is destroyed. Styles assigned from QML are still left untouched, and the curve no longer keeps a dangling reference when an assigned style is destroyed before it; it emits lineStyleChanged and repaints instead.
  • Appending the same axis to extraAxes twice no longer registers it twice and reserves its layout space twice, and reading an out-of-range extraAxes index returns null instead of tripping an assert.
  • A very large series or rectangle count that would produce a data texture taller than a safe cross-GPU limit now logs a clear warning explaining why it may render nothing, instead of failing silently.
  • DashLine now rejects a pattern containing a negative segment, and warns when a pattern is longer than the eight segments the renderer supports instead of silently dropping the rest.
  • mouseMoved now fires for a plain cursor move over the plot, not only while a mouse button is held, matching its documented behavior.
  • Axes are no longer given a negative width or height when the plot item is smaller than its padding plus the space its axes reserve.
  • LineCurve no longer changes its own position or size from updatePaintNode(), which runs on the render thread with the threaded render loop and is not a safe place to mutate QQuickItem geometry. It now reads the plot rect that QAccelPlot already assigns on the GUI thread instead.
  • LineCurve::appendData() updates the reported data range and the GPU render buffer incrementally instead of rescanning and rebuilding the whole curve on every call, so streaming N points costs O(N) work instead of O(N²).
  • RectangleList re-uploads its data texture when the scene-graph node is recreated (e.g. after axes are temporarily unset), instead of leaving a freshly created node with an empty texture until new data arrives.
  • DataAnchor no longer dereferences a dangling pointer after its xAxis or yAxis is destroyed elsewhere; the axis reference is cleared automatically instead.
  • A horizontal-only wheel or touchpad scroll no longer zooms the plot out; it is now ignored by the zoom handler and passed through instead.
  • Tick labels near zero no longer render as a misleading "-0.00" when a tiny negative value from accumulated tick-position arithmetic rounds to zero at the display precision.
  • Vertical gradients on markers now match the orientation of line strokes and fills instead of rendering upside down.
  • Changing an axis ticker's tickCount or subtickCount now refreshes the plot grid immediately instead of leaving it stale until the next pan or zoom.
  • The plot area is now relaid out when an axis's axisLinePadding, orientation, or ticker tickLengthIn/subtickLengthIn changes at runtime, instead of only on visible or layoutSize changes.
  • Extra axes now respect their side: a horizontal extra axis with side: Top stacks above the plot instead of always below it, and a vertical extra axis now reserves layout space and stacks on its declared side (Left or Right) instead of always overlapping the plot's left edge with no reserved space.
  • Log-scale axis labels no longer collapse to "0.0" or "100.0" for small or large tick values; each major tick's own magnitude is now used to derive its label precision.
  • Axis::rescaleToData() (double-click rescale) no longer does nothing for flat data — a constant series or a single point — and synthesizes a small viewport around the value instead, proportional to the value's own magnitude so a very small nonzero value isn't rendered indistinguishable from zero. A log-scale axis with only non-positive data now gets a valid, all-positive synthesized viewport instead of a mismatched positive-min/non-positive-max range.
  • Enabling logScale (via the property, toggleLogScale(), or the L key) while the current viewport is non-positive now clamps it to a valid positive range instead of collapsing every curve to a single point.
  • A non-finite X or Y data range on a PlotSeries no longer blocks the other axis's range update; each axis's range is now validated and reported independently.
  • Tick labels are now formatted on the GUI thread before rendering, rather than inside Axis::paint(), which runs on the render thread with the threaded render loop. A tickLabel JavaScript callback is therefore never invoked from the render thread, and it now receives tickStep as its second argument (previously always undefined).
  • Preserved double precision in RectangleList for modern Unix-epoch timestamps and large coordinates: rectangles are stored and their data range computed in double precision, and rendering uses an origin-relative float buffer instead of storing raw coordinates as float. A new setData(const double*, int) overload accepts double-precision data directly.
  • A single ±Inf coordinate is now skipped when computing a curve's axis data ranges instead of making that range non-finite, and all-NaN data no longer reports an inverted range.
  • NaN samples no longer make adjacent valid line segments disappear or produce backend-dependent artifacts.
  • On Qt 6.2, the legend now uses the dark palette's background, border, and text colors instead of falling back to a white box with dark text.

[0.1.0] — 2026-09-08

Added

  • GPU-accelerated LineCurve rendering integrated with a QML-first Plot component and C++ PlotView API.
  • Efficient data-ingestion paths for QML and C++, including thread-safe buffer handoff for real-time data produced by worker threads.
  • Interactive linear and logarithmic axes with pan, zoom, configurable ticks, multiple label formatters, and support for primary, secondary, and extra axes.
  • Curve styling with solid and dashed lines, point markers, anti-aliasing, gradient fills and strokes, and animated draw and morph transitions.
  • Hover detection for curves and efficiently batched data-space rectangles.
  • Data-anchored QML annotations for labels, regions, and custom overlays.
  • Configurable plot grids, automatic legends, and light and dark color palettes.