Data inspection¶
PlotInspector shows a crosshair, a marker on every series, and a tooltip at
the cursor. SelectionTool selects a region and reports its statistics.
import QAccelPlot as QAccelPlot
QAccelPlot.Plot {
id: plotView
// Bind each series to its axes.
QAccelPlot.PlotInspector {
plot: plotView
QAccelPlot.Crosshair { axisLabels: true }
QAccelPlot.InspectionMarkers {}
QAccelPlot.InspectionTooltip {}
}
QAccelPlot.SelectionTool { plot: plotView }
}
- Components declared inside a
PlotInspectoruse it and are drawn in declaration order, the last one on top. A component declared elsewhere needsinspector:set and is not restacked. - They are children of
plotView.overlay, an item above the series and the legend. Parent your own overlays to it instead of choosing azrelative to the series. - Shift + left drag selects a region; Escape clears it. Ordinary left dragging still pans.
Rectangle zoom defaults to Ctrl + left drag. If both are
set to the same gesture, SelectionTool takes it.
Inspector¶
PlotInspector queries every visible LineCurve,
PointCloud, and HeatmapSeries of the plot at the cursor. Other series types
have no row. A heatmap reports the cell under the cursor in every mode, at its
center; radius, interpolate, and summaries do not apply to it, and
snapToDataPoint moves both crosshair coordinates to the center.
| Property | Effect |
|---|---|
mode |
NearestX reports each series at the cursor's X. NearestY does the same at the cursor's Y, for series whose independent variable is Y. NearestXY picks the data point closest on screen. |
radius |
Pick distance in logical pixels. In NearestX and NearestY it only applies beyond a series' extreme data points; between two data points a series always matches. |
interpolate |
In NearestX and NearestY, report the point on the line between two consecutive data points. On a step line it is on the step, and its index is the data point holding the value. |
snapToDataPoint |
Move the crosshair to the closest matching data point. |
summaries, summaryRadius |
Add the count and Y statistics of the data points within summaryRadius pixels of the cursor. Use it for dense data, where one pixel column holds many data points. |
includedSeries, excludedSeries |
Restrict the inspected series. |
The inspector reports active, crosshairPosition in plot-local pixels, the
cursor in data units (cursorX, cursorY, with their formatted texts) and in
pixels (cursorPixelX, cursorPixelY), validCount, and model.
Tooltip rows¶
inspector.model has one row per inspected series, updated in place as the
cursor moves. Replace InspectionTooltip.rowDelegate to change a tooltip row,
and declare the roles it uses as required properties:
QAccelPlot.InspectionTooltip {
rowDelegate: Text {
required property bool valid
required property string seriesName
required property string yText
visible: valid
text: seriesName + " = " + yText
}
}
InspectionRowModel lists the roles. Text roles such as yText
use the axis' tick formatter at a precision that follows the zoom level.
valueText holds the value of a heatmap cell or a colored PointCloud point
with up to six significant digits; the default row shows it after the
coordinates. pixelX and pixelY place the matched data point in plot-local
pixels, like cursorPixelX and cursorPixelY.
Cursor from code¶
Set followPointer: false and write cursorX, cursorY, or both to place the
cursor in data coordinates. With one coordinate, series are matched along that
axis in every mode and heatmaps have no match. Link two plots by binding one
inspector to the other:
QAccelPlot.PlotInspector { id: top; plot: topPlot }
QAccelPlot.PlotInspector { plot: bottomPlot; followPointer: false; cursorX: top.cursorX }
To drive the cursor from a pixel position, such as a scripted pointer, write
cursorPixelX and cursorPixelY in plot-local pixels. The cursor stays on
those pixels when the axes pan or zoom, and cursorX and cursorY report the
data under it. A binding such as cursorX: plot.pixelToDataX(x) goes stale
instead, because pixelToDataX() has no change signal.
QAccelPlot.PlotInspector {
plot: plotView
followPointer: false
cursorPixelX: pointer.x // pointer is in plot-local pixels
cursorPixelY: pointer.y
}
Each coordinate is in the unit it was last written in: writing cursorX after
cursorPixelX places X in data units again.
One pixel can span several data points. To rest on a known data point, write
its cursorX and cursorY instead.
stepCursor(n) moves the cursor n source records along the first matching
XY series and stops following the mouse pointer; use it for keyboard
navigation.
Queries¶
Every series exposes its queries as series.inspection. Call them on the series'
thread. Pixel arguments are series-local logical pixels: map a plot-local
position with series.mapFromItem(plot, position).
const position = curve.mapFromItem(plotView, inspector.cursorPixelX, inspector.cursorPixelY)
const dataPoint = curve.inspection.nearestByX(position.x)
if (dataPoint.valid)
console.log(dataPoint.index, dataPoint.x, dataPoint.y)
A data point has x and y in data units and pixelX and pixelY in
series-local pixels, the frame of the query arguments. value is the colormap
value of a PointCloud point or a heatmap cell, and NaN for other series and
interpolated points.
| Query | Methods |
|---|---|
| A data point by index | dataPointAt() |
| Nearest valid data point | nearest(), nearestByX(), nearestByY() |
| Data points on either side and the point between them | bracketByX(), bracketByY() |
| Y statistics of a region or an X interval | summarize(), summarizeRange() |
| Source indices inside a region, in pages | indices() |
| Native record of a bar, rectangle, band, or heatmap series | recordAt(), recordAtPosition() |
| Heatmap cell at a position, as a data point | dataPointAtPosition() |
Results carry a status and a valid flag. Compare status with
QAccelPlot.Inspection.Ready, NoMatch, Preparing, or another status. A
query that does not apply to the series returns Unsupported.
SeriesInspection specifies regions, tie-breaking, and
paging.
Readiness¶
| Data | Behavior |
|---|---|
| X or Y finite and non-decreasing | Searched in place. No preparation and no index; appendData() keeps queries available. |
| Unordered, up to 20 000 records | Scanned per query. No preparation. |
| Unordered, more records | Indexed on a worker thread. Queries return Preparing until inspection.status is Ready; statusChanged announces it. |
nearestByX(),bracketByX(), and their Y counterparts need the order along their own axis.prepare()starts indexing before the first query.- Any data change discards the index. A stream that replaces unordered data
faster than it can be indexed never becomes
Ready. - The index takes about 40 MB per million valid data points;
inspection.indexBytes()reports the actual size.
Selection¶
SelectionTool selects a Box, an XRange, or a YRange.
button, modifiers, and minimumSize configure the gesture; the modifiers
must match exactly and a shorter drag only clears the selection.
- The region is
xMin,xMax,yMin,yMaxin the coordinates ofxAxisandyAxis, which default to the plot's primary axes. A range selection is unbounded in its other dimension. - Visible XY series bound to the axis of every bounded dimension are selected, so an X range also covers series on a secondary Y axis.
modelhas one row of statistics per selected series, recomputed when data changes.indices(series, offset, limit)pages through the selected data points.select(xMin, xMax, yMin, yMax)sets the region from code;clear()removes it.selectionChangedreports a new or cleared region,completeda finished gesture.- The tool draws the gesture and the region with
fillColorandborder.
To draw them yourself, set visible: false and bind an overlay item to
selectionRect: the gesture or region in plot pixels, empty without either.
Gestures and the selection keep working.
QAccelPlot.SelectionTool {
id: selection
plot: plotView
visible: false
}
Rectangle {
parent: plotView.overlay
x: selection.selectionRect.x
y: selection.selectionRect.y
width: selection.selectionRect.width
height: selection.selectionRect.height
visible: width > 0 && height > 0
radius: 4
color: "transparent"
border.color: "orange"
}
selectionRect follows panning and zooming and extends past
plotView.plotRect when the region is partly out of view. To keep your item
inside the plot area, put it in an Item with clip: true that covers
plotRect.
Complete source: examples/interaction/data_inspection