feat(examples): a three-row synced Figure demo, on a GLFW host that draws one
The multi-plot example the phase exists for: three plots stacked in one Figure, sharing one x link with following armed, each row carrying its own named signals and its own legend, driven by six StreamSeries at 500 kS/s. Two cursors and a region with an exact statistics readout reach the direct manipulation of spec §5 in the same frame, and PLOT_DEMO_SYNC=1 is a self-checking mode that exits non-zero unless all three rows hold one range and the shared right edge keeps tracking the newest sample through a zoom, a pan on another row and more arriving data. The GLFW host gains the figure mode the demo needs: set_figure() makes the run loop draw the Figure instead of its own plot and route each pointer, wheel and key event to the row it lands in, through one Controller per row (row_controller()). All of it is opt-in; the single-plot path is untouched.
This commit is contained in:
1 parent
770da4c2b2
commit
942f88c568
9 files changed
+917
-39
No files matched your search
+42
-4
@@ -86,6 +86,10 @@ constexpr plot::Color kExtraCursorColors[] = {plot::Color::hex(0xFF6B6B),
|
||||
plot::Color::hex(0xB08CFF),
|
||||
plot::Color::hex(0x6BE3FF),
|
||||
plot::Color::hex(0xE8E86B)};
|
||||
/// The region's fill and bound stroke, in colours nothing else here draws, so a pixel
|
||||
/// count of either is about the region.
|
||||
constexpr plot::Color kRegionFill = plot::Color::hex(0x33FF00, 0.35f);
|
||||
constexpr plot::Color kRegionEdge = plot::Color::hex(0xFF00FF);
|
||||
|
||||
/// Logical pixels. The widget's framebuffer is `devicePixelRatioF()` times this.
|
||||
constexpr int kWindowWidth = 1200;
|
||||
@@ -267,7 +271,8 @@ int main(int argc, char** argv) {
|
||||
{"time", {-0.5, 0.5}, true, plot::AxisPlace::Bottom, false, plot::TickFormat::Time});
|
||||
const u32 axis_y = graph.add_y_axis(
|
||||
{"signal", {-4.0, 4.0}, true, plot::AxisPlace::Left, false, plot::TickFormat::Si});
|
||||
const u32 trace = graph.add_trace({&stream, kTraceColor, 1.5f, axis_x, axis_y});
|
||||
// Named, so the plot's legend -- on by default -- lists the signal.
|
||||
const u32 trace = graph.add_trace({&stream, kTraceColor, 1.5f, axis_x, axis_y, "signal"});
|
||||
|
||||
// Snapped cursors sit exactly on a sample, so the readout measures samples and
|
||||
// not a rounded position between two of them. The pair and its measurement are
|
||||
@@ -278,6 +283,16 @@ int main(int argc, char** argv) {
|
||||
graph.set_cursor_snap(cursor_b, plot::SnapMode::NearestSample);
|
||||
const u32 measure = graph.add_measure(cursor_a, cursor_b, trace);
|
||||
|
||||
// One region, so the direct manipulation of spec §5 is reachable in this demo too: a
|
||||
// shaded interval with the statistics readout in the exit frame. Its bounds ride the
|
||||
// live window until the user drags a handle, exactly as the cursors do.
|
||||
plot::Region region_desc;
|
||||
region_desc.snap = plot::RegionSnap::Free;
|
||||
region_desc.fill = kRegionFill;
|
||||
region_desc.edge = kRegionEdge;
|
||||
region_desc.label = "roi";
|
||||
const u32 region = graph.add_region(region_desc);
|
||||
|
||||
// --- the window, its toolbar and the widget ----------------------------
|
||||
QMainWindow window;
|
||||
window.setWindowTitle("plot qt demo");
|
||||
@@ -303,7 +318,7 @@ int main(int argc, char** argv) {
|
||||
Meter meter;
|
||||
// The cursors ride the live window until the user takes over: the first
|
||||
// ctrl+drag on a cursor, or a pan/zoom that clears the x axis' auto scale,
|
||||
// stops them where the user put them.
|
||||
// stops them where the user put them. The region's bounds ride the same window.
|
||||
bool cursors_follow = true;
|
||||
plot::usize extra_cursor = 0;
|
||||
|
||||
@@ -317,13 +332,18 @@ int main(int argc, char** argv) {
|
||||
if (p.y_axis(axis_y).auto_scale) p.auto_fit_y(axis_y);
|
||||
|
||||
if (cursors_follow) {
|
||||
if (widget->controller().drag_mode() == plot::input::DragMode::MoveCursor ||
|
||||
!p.x_axis(axis_x).auto_scale) {
|
||||
const plot::input::DragMode mode = widget->controller().drag_mode();
|
||||
const bool dragging = mode == plot::input::DragMode::MoveCursor ||
|
||||
mode == plot::input::DragMode::MoveRegion ||
|
||||
mode == plot::input::DragMode::ResizeRegionLeft ||
|
||||
mode == plot::input::DragMode::ResizeRegionRight;
|
||||
if (dragging || !p.x_axis(axis_x).auto_scale) {
|
||||
cursors_follow = false;
|
||||
} else {
|
||||
const plot::Range xr = p.x_range(axis_x);
|
||||
p.set_cursor_x(cursor_a, xr.min + 0.35 * xr.span());
|
||||
p.set_cursor_x(cursor_b, xr.min + 0.65 * xr.span());
|
||||
p.set_region(region, xr.min + 0.40 * xr.span(), xr.min + 0.60 * xr.span());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +440,24 @@ int main(int argc, char** argv) {
|
||||
static_cast<double>(after.axes.w), static_cast<double>(after.axes.h),
|
||||
static_cast<double>(after.axes.x), static_cast<double>(after.axes.y));
|
||||
|
||||
// The region's last-frame geometry and its exact statistics, so the screenshot's
|
||||
// pixels can be read against the rects the layout measured (`Series::reduce/sum/sumsq`
|
||||
// over the interval, never the pyramid's bucket forms).
|
||||
for (const plot::RegionLayout& rl : after.regions) {
|
||||
if (rl.region != region) continue;
|
||||
const plot::RegionStats& rs = graph.region_stats(region, trace);
|
||||
std::printf("[qt_demo] region %u: fill x %.1f y %.1f w %.1f h %.1f, bounds at %.1f and"
|
||||
" %.1f\n",
|
||||
region, rl.fill.x, rl.fill.y, rl.fill.w, rl.fill.h,
|
||||
static_cast<plot::f64>(plot::handle_column(rl.left_handle)),
|
||||
static_cast<plot::f64>(plot::handle_column(rl.right_handle)));
|
||||
if (rs.valid) {
|
||||
std::printf("[qt_demo] region %u: x [%g, %g] s, n %llu, mean %g, rms %g, min %g, max"
|
||||
" %g, integral %g\n",
|
||||
region, rs.x0, rs.x1, static_cast<unsigned long long>(rs.count), rs.mean,
|
||||
rs.rms, rs.min, rs.max, rs.integral);
|
||||
}
|
||||
}
|
||||
if (screenshot != nullptr && screenshot[0] != '\0') {
|
||||
const bool written = dump_widget_ppm(image, screenshot);
|
||||
std::printf("[qt_demo] screenshot %s: %s\n", screenshot, written ? "written" : "FAILED");
|
||||
|
||||
Reference in new issue
Block a user