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 aColormap, with aColorBarkey, a Heatmap example, and cell inspection throughPlotInspectorandinspection.dataPointAtPosition(). Heatmaps draw on logarithmic axes, andxSpacing/ySpacing: HeatmapSeries.Logspaces cells evenly in log10. valueTextinspection role with the value of a heatmap cell or a coloredPointCloudpoint. The defaultInspectionTooltiprow shows it.- Legend entries described in C++:
PlotSeries::legendEntry()returns aLegendEntry, andLegendModellists the entries of the visible series that have one, such asPlot.legendModel. - A
HeatmapSeriestab in theshowcases/performanceexample, streaming a scrolling spectrogram of up to 100M cells. - Colormapped bars:
BarSeries.colormapcolors each bar by its value or, withcolorSource: 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 aQImage, 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 withsetErrorData(), and animated byMorphTransitionandDrawTransition. Includes an Error Bars example. PlotSeries.hoverEnabledturns hover off for one series and leaves it to the series beneath.hoveredmoved toPlotSeries, soPointCloud,BarSeries,RectangleSeries, andErrorBarSeriesreport it too.PlotSeries.counton every series, includingLineCurve(points) andHeatmapSeries(cells,columns×rows).antialiasing: truesmoothsRectangleSeriesandBarSeriesedges. It is off by default.- Step lines via
LineCurve.stepMode(Before,After, orCenter): the fill, dash pattern, hover, and interpolated inspection follow the steps. Includes a Step Lines example. PlotView.rectangleZoom.visible: falsehides the drawn zoom rectangle, so you can drawselectionRectyourself.PlotInspector.cursorPixelXandcursorPixelYplace the cursor in plot-local pixels; it stays on those pixels when the axes pan or zoom.- Named categories on
BarSeriesandRectangleSeries:categorieslistsCategoryobjects with avalue,name, andcolor, a data point'scategoryis a value or, in QML, a name, and the legend shows one row per category throughPlotSeries::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, andscripts/frames-to-gif.pyturns them into a GIF.
Changed¶
- The C++ plot item class
QAccelPlot::QAccelPlotis nowQAccelPlot::PlotView, its QML name, in<QAccelPlot/PlotView.hpp>. QML is unchanged. Grid.lineWidthis nowgridLineWidth, matchingsubGridLineWidth. In C++, usegridLineWidth(),setGridLineWidth(), andgridLineWidthChanged().- Marker shapes are a standalone
MarkerShapeenum instead of aPlotSeriesenum. ReplaceLineCurve.DiamondorPointCloud.CirclewithMarkerShape.DiamondorMarkerShape.Circlein QML, andPlotSeries::MarkerShapewithMarkerShape(<QAccelPlot/series/MarkerShape.hpp>) in C++. Values are unchanged. PlotMouseEvent.buttonisQt.NoButtonfor a move instead of the held buttons cast into one value; the newbuttonsholds them.reset()is no longer public.Colormap.normis nowlogScale: bool, likeAxis.logScale. Replacenorm: Colormap.LogwithlogScale: truein QML, andsetNorm(Colormap::Normalization::Log)withsetLogScale(true)in C++. TheColormap::Normalizationenum is removed.- Renamed
PlotInspector.positiontocrosshairPosition, andpositionChanged()tocrosshairPositionChanged(). - Inspection data points place a point as
x,y(data units) andpixelX,pixelY(series-local pixels). ReplacepixelPosition.xwithpixelX, and the inspection row rolepixelPosition(plot-local) withpixelXandpixelY. In C++,InspectionDataPoint::positionandx()/y()are now thexandymembers. - Renamed
SelectionTool.rectangleVisibletovisibleandpixelRecttoselectionRect, matchingPlotView.rectangleZoom. Signals and C++ accessors follow:visibleChanged(),isVisible(),setVisible(),selectionRect(),selectionRectChanged(). BarSeriesandRectangleSeriestakecategoriesinstead ofcategoryColors: replacecategoryColors: [a, b]withcategories: [Category { value: 0; color: a }, Category { value: 1; color: b }].setCategories()for the data points is nowsetDataPointCategories(). A QMLcategorythat is neither a whole number nor a category name is ignored with a warning.- Series use the
antialiasingproperty inherited fromItem.LineCurve.antialiasingEnabled,PointCloud.antialiasingEnabled, andLegendEntry.antialiasingEnabledare nowantialiasing.BandSeriesedge lines andErrorBarSeriesfollow it too. - Outlines use one
bordergrouped property withcolorandwidth.PlotView.rectangleZoom.borderColor,SelectionTool.borderColor, andColorBar.borderColor/borderWidthare nowborder.color/border.width. The rectangle zoom and selection outlines can now be wider than 1 px. In C++,PlotBorderandRectangleBorderare nowBorder(<QAccelPlot/Border.hpp>). ColorBar.seriestakes anyColormappedSeries, the new base ofPointCloud,HeatmapSeries, andBarSeries. In C++,ColorBar::series()returns aColormappedSeries*.Legendtakes amodelinstead ofseries. Hidden series have no entry, and unnamed series are listed as "Series N".inspection.statusisReadyfor bar, rectangle, band, and heatmap series instead ofUnsupported. Queries that do not apply to them still returnUnsupported.- A
LineCurvewith 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. LineCurvemarkers read their positions from the GPU data texture, so data updates no longer rebuild a vertex buffer per marker.- When a
LineCurvepoint count grows, only the added points' vertices are written. - Data transitions run on Qt's animation clock, like QML animations, so an
installed
QAnimationDrivercan step them frame by frame. Adurationof 0 ends at the next frame. - The
showcases/performanceexample presents without vsync, so the refresh rate no longer caps display FPS.
Removed¶
SeriesInspection.supported. A query that does not apply to a series returnsInspection.Unsupported.SeriesInspection.maximumPageSize.indices()capslimitat 4096 and each page reports the size used inlimit.PlotView.pointerPosition,pointerInside, andpointerChanged(). UsePlotInspector.cursorPixelX,cursorPixelY, andactive, or aHoverHandler.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(). UsesetDataF()orpostData(); the curve builds its own vertex cache.- The
showcases/pulsarexample. - 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 theQACCELPLOT_BUILD_BENCHMARKSoption. Measure frame rates with the Performance Lab. RectVertexCachefrom the public headers. It was an internal helper ofBarSeriesandRectangleSeries.effects/GradientCoordinateUtils.hppandeffects/GradientUtils.hppfrom the public headers. Their helpers were internal to the gradient effects,Colormap, andLineCurve.
Fixed¶
LineCurve,BarSeries,RectangleSeries, andBandSeriesno longer hover records beyond their GPU capacity, which are not drawn.- Changing
PointCloud.hoverRadiusorErrorBarSeries.hoverRadiusupdateshoveredIndexwithout waiting for the mouse to move. Colormap.stopsreads boundGradientStops 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
.glslfile 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.rectangleZoomandzoomToRect(), with theme colors and a Point cloud example. - Data inspection via
PlotInspectorandSelectionTool: 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.overlayfor items drawn above the series, and the pointer position viapointerPositionandpointerInside.Axis.formatValue(), which formats a value at the precision of the current zoom.RectangleSeries:rectangleAt(),rectangleIndexAt(),clearData(),setData(std::vector<double>&&, int), andpostData().RectangleSeriesspans: infinite or omitted edges reach the plot edge.RectangleSeries.minimumWidthandminimumHeight, 1 px by default.RectangleSeriescategories:category,categoryColors, andsetCategories().RectangleSeries.border.widthandborder.color.RectangleSeries.hoverColor.RectangleSeries:setDataF()and floatpostData()overloads.SpatialGrid::buildF().RectVertexCache.BarSeries:orientation,barWidth,barOffset,baselineValue,barAt(), andbarIndexAt().BarSeriesranged bars with their ownfromandto, viasetData()andsetRangedData().BarSeries.transition:MorphTransitionandDrawTransitionanimate bar updates.PointCloud.transition:MorphTransitionandDrawTransitionanimate point updates.LineCurve.hoverRadius.- The
plot_types/bar_chartexample. - The
plot_types/state_timelineexample. BandSerieswithedges,valueAt(), andhovered.- The
plot_types/bandsexample. - Histograms via
Histogram: equal or uneven bins, counts or density, as data for aBarSeries, with a Histogram example. Axis.autoRescale, which fits the viewport to the data range on every data update.PlotSeries::DataBoundsoverloads ofsetData()andsetDataF(), which take the data extents instead of scanning for them.PlotSeries::xDataRange()andyDataRange()are public.ColorBar.interactive: dragging pans the colormap range, the wheel zooms it, and a double-click orrescaleToData()resolves it from the data again.hoveredreports the cursor over it.
Changed¶
PlotSeries::setData(),setDataF(), andpostData()are no longer virtual: C++ subclasses pass their data point layout to thePlotSeriesconstructor.- Renamed the C++ and QML
RectangleListtype toRectangleSeries. Include<QAccelPlot/series/RectangleSeries.hpp>in C++ code. GradientStroke::payload()andGradientFill::payload()return a reference to a snapshot that the effect updates on the GUI thread. The newLineCurveEffect::refresh()re-reads inputs that change without a notification.DataTransition::start()andadvance()take aDataTransition::Runthat holds one element's animation state.DataTransition::interpolate()takesDataTransition::Datasetarguments, andstart()astridefor points of more than two values.DrawTransitionstarts from one point instead of two.- Moved
RectangleSeries.hpptoQAccelPlot/series/. - Replaced
RectangleSeries::setData(const float*, int)withsetDataF(const float*, int). PointClouduses half the GPU vertex memory per point.PointCloudandRectangleSerieshover scans live data instead of rebuilding its spatial index after every data update.- The
showcases/performanceexample hasLineCurve,PointCloud,RectangleSeries, andBarSeriestabs, each with options for series count, ingestion API, hover, and rendering. Axis::rescaleToData()emitsrangeChanged()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 withautoRescale, or aDataRangegradient reads it. Axis.dataMinChanged()anddataMaxChanged()also announce a data update whose range has not been computed yet.- Renamed
LineCurve::setDataFNoRangeWithCache()tosetDataFWithCache(). - Renamed
Axis::updateDataRange()tosetDataRange(). Axis.orientation,ColorBar.orientation, and thedirectionofGradientFillandGradientStroketakeQt.Horizontal/Qt.Vertical. This replacesAxis.Orientation,ColorBar.Orientation, andGradientDirection.- Renamed
GradientFillandGradientStrokeproperties:gradientValueMin→valueMin,gradientValueMax→valueMax,gradientValueMinSource→valueMinSource, andgradientValueMaxSource→valueMaxSource. - Renamed
Axis.axisTitlePaddingtolabelPaddingandAxis.axisLinePaddingtobaselinePadding. Axis.labelPadding,Axis.baselinePadding, andzoomScaleFactorofAxisandColorBarareqreal.buttonis aQt::MouseButtonandmodifiersaQt::KeyboardModifiersonPlotMouseEvent,SelectionTool, andPlotView.rectangleZoom, instead ofint.- Renamed
nearly_equal()inMathUtils.hpptonearlyEqual(). - The QML module version follows the project version, 0.4 in this release,
instead of 1.0. Replace
import QAccelPlot 1.0withimport QAccelPlot. PlotView::rescaleAllAxes()is public instead of protected.
Removed¶
- The
setDataNoRange()andsetDataFNoRange()setters. UsesetData()andsetDataF(), which no longer scan. To keep a range the application maintains, pass it asPlotSeries::DataBoundsinstead of settingAxis.dataMin/dataMax. PlotSeries::xDataRangeChanged()andyDataRangeChanged(). ReadxDataRange()andyDataRange(), or connect toAxis.dataMinChanged()/dataMaxChanged().
Fixed¶
TextTickLabelFormatterreturns 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. Plotwithlegend: nullno longer logs a TypeError.- On a logarithmic axis,
RectangleSeriesedges 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.
LineCurvewith both a line and markers is hovered along the line, not only on markers.- Hovering a
RectangleSeriesorBarSerieswhose records share one coordinate far from zero, such as a zero-width rectangle at a nanosecond timestamp, no longer crashes. GradientFillon dense data reaches the curve's peaks and troughs.- Gradient effects with a
DataRangebound use the curve's own data extent, not the whole axis range. LineCurveandPointCloudkeep double precision when the viewport is far from the first data point, e.g. at the end of a long timestamp series.- Hovering a
PointCloudwhose points lie on a long horizontal line no longer tests every point. PointCloudno longer hovers points beyond the GPU texture capacity, which are not drawn.Colormapnow drops destroyedstopsand updates its ramp when a stop changes.Colormapignores null entries instopsinstead of crashing.- A series whose log-scale axis was destroyed refreshes its data ranges when bound to a linear axis.
RectangleSeriesandBarSerieskeep double precision when the viewport is far from the first record.LineCurvetransitions now advance on the GUI thread, soDataTransition.runningchanges, 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
PlotViewas its parent, such asnew LineCurve(plot), is now listed inPlotView.seriesand 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/performanceandshowcases/pulsarexamples no longer hang on exit. LineCurveno longer reads the QMLGradientof aGradientStrokeorGradientFillfrom 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 thatGradientdoes not signal still show up.- Curves sharing one
DataTransitionanimate to their own data. - Replacing, clearing, cancelling, or destroying a running
LineCurvetransition, or callingappendData()during it, shows the new data instead of freezing the animation. - A
LineCurvetransition that starts from float data inNanGapMode.Connectno longer crashes when the curve is hovered. RectangleSeriesno longer blocks hover for series underneath it.RectangleSeriesandBarSeriesskip 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
dataMinanddataMaxto 0 and 1. RectangleSeriesandPointCloudrender up to about 16M rectangles or 22M points (data texture rows are 8192 texels wide).LineCurve,RectangleSeries, andBarSeriesdraw only the records their GPU buffers hold and warn about the rest, instead of overflowing the vertex buffer. These series,BandSeries, andPointCloudwarn 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 destroyedPlotViewreleases its children, before their own members are gone, so handlers ofseriesChangedno 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, andPentagon, and aPixelmarker that draws each sample as a single pixel for very dense scatter plots. - Hollow markers: set
marker.filledtofalseto outline filled shapes withmarker.strokeWidthpixels. Legend symbols follow the series. - The
styling/markersexample shows every shape. Click a shape to draw a scatter plot with it, and adjust marker size, outline, and opacity. - The
plot_types/parametric_curvesexample 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_cloudexample 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 floatpostData().PointCloudseries for large unconnected scatter data. Its markers use the samemarkergrouped property asLineCurve.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 areversedflag.GradientFill.colormapandGradientStroke.colormaptake a colormap as an alternative togradient, which it overrides when both are set.PointCloud.colormapcolors points by their per-point values.ColorBar, a continuous key for aPointCloudcolormap. It draws the ramp with ticks for the series' resolved value range, followsLinearandLognormalization, and redraws when the colormap or range changes. Vertical and horizontal orientations; ticks are configured throughticker, as onAxis.
Changed¶
- Public headers are now included with a
QAccelPlot/prefix, for example#include <QAccelPlot/series/LineCurve.hpp>, both when QAccelPlot is embedded withadd_subdirectoryorFetchContentand when it is installed. The library sources moved toQAccelPlot/src/QAccelPlot/. Replace unprefixed includes such as"series/LineCurve.hpp". LineCurve.markerShapeandmarkerSizemoved tomarker.shapeandmarker.size.- Examples are grouped by category under
examples/:plot_types/,styling/,axes/,data/,interaction/, andshowcases/, withquickstart/at the top. Renamed examples:axis_formats→axes/tick_formats,custom_axis→axes/multiple_axes,interactive_tools→interaction/measurement_tools,performance_showcase→showcases/performance, andpulsar_showcase→showcases/pulsar. Their executables are renamed to match, for exampleQAccelPlotExampleTickFormats. - 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), anddata/missing_data(invalid samples and gaps).
Removed¶
LogTickLabelFormatter. The defaultNumericTickLabelFormatternow labels logarithmic axes with the same superscript powers of ten.
Fixed¶
- The Qt Quick
opacityproperty, set on a series or inherited from a parent item, now applies toLineCurvelines, markers,GradientStroke, andGradientFill, and toPointCloudandRectangleList. 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, 2instead of0.0, 1.0, 2.0, and steps of 0.1 and 0.2 read0.1, 0.2instead of0.10, 0.20. All labels on a linear axis keep the same number of decimals, for example0.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 of0.010, 0.10, 1.0, 10, 100. Custom formatters can override the newTickLabelFormatter::doFormatLogTick();tickLabelcallbacks are unchanged. LineCurvenow 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.
RectangleListnow 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.
LineCurveno longer keeps a danglingtransitionpointer when an externally owned data transition is destroyed; the property is cleared and its change is reported.- Canceling, replacing, or destroying a
LineCurvetransition 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
LineCurvegradient 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
tickCountto 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
antialiasingFeatherramp 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, andTriangleDownmarkers 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.GradientStrokeandGradientFillnow keep aFixedgradient value bound when the other bound usesDataRange. Previously both bounds were taken from the data range.GradientStrokeandGradientFillnow redraw when a stop of theirgradientchanges color or position at runtime.
[0.2.0] — 2026-09-16¶
Added¶
- Per-axis
layoutSizecontrol for explicitly reserving horizontal-axis height or vertical-axis width. - Automatic side assignment for the four named plot axes:
xAxisuses the bottom,x2Axisthe top,yAxisthe left, andy2Axisthe 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.gapsgrouped property.gaps.nanModeselectsNanGapMode.Break(default) orNanGapMode.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.
MorphTransitionno longer interpolates from or to non-finite coordinates: new gaps appear immediately and samples leaving a gap jump to their target.- Renamed
RectangleList::setRawData()tosetData(), matching the naming of theLineCurvedata-setting APIs. - Default plot, axis, grid, series, and legend colors now come from the
built-in dark palette instead of generic Qt colors. The
Colorspalette 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 theFingestion APIs float-based. - Reassigning a
LineCurve'seffectslist no longer deletes the effect objects, and effects destroyed elsewhere are removed from the list instead of leaving dangling entries. - A running
LineCurvetransition no longer overwrites data pushed throughappendData()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
tickWidthvalues (e.g.1.5) instead of truncating to an integer pixel width. LineCurveno longer leaks the defaultSolidLineit creates for itslineStyle: 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 emitslineStyleChangedand repaints instead.- Appending the same axis to
extraAxestwice no longer registers it twice and reserves its layout space twice, and reading an out-of-rangeextraAxesindex returnsnullinstead 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.
DashLinenow 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.mouseMovednow 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.
LineCurveno longer changes its own position or size fromupdatePaintNode(), which runs on the render thread with the threaded render loop and is not a safe place to mutateQQuickItemgeometry. It now reads the plot rect thatQAccelPlotalready 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²).RectangleListre-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.DataAnchorno longer dereferences a dangling pointer after itsxAxisoryAxisis 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
tickCountorsubtickCountnow 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 tickertickLengthIn/subtickLengthInchanges at runtime, instead of only onvisibleorlayoutSizechanges. - Extra axes now respect their
side: a horizontal extra axis withside: Topstacks above the plot instead of always below it, and a vertical extra axis now reserves layout space and stacks on its declaredside(LeftorRight) 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 theLkey) 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
PlotSeriesno 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. AtickLabelJavaScript callback is therefore never invoked from the render thread, and it now receivestickStepas its second argument (previously alwaysundefined). - Preserved double precision in
RectangleListfor 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 newsetData(const double*, int)overload accepts double-precision data directly. - A single
±Infcoordinate is now skipped when computing a curve's axis data ranges instead of making that range non-finite, and all-NaNdata no longer reports an inverted range. NaNsamples 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
LineCurverendering integrated with a QML-firstPlotcomponent and C++PlotViewAPI. - 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.