From 0c228c4822844f3e6dd2fcfd5fb5a21543d39bac Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 4 Nov 2026 07:04:07 +0100 Subject: [PATCH] pin deps/plotter: per-column x axes, tighter cell gap; docs --- deps/plotter | 2 +- docs/USER-GUIDE.md | 4 ++-- docs/claude/build-and-run.md | 13 +++++++++++-- docs/claude/invariants-plot-and-layout.md | 13 ++++++++++--- help/C/org.udpscope.app/layout.page | 4 ++-- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/deps/plotter b/deps/plotter index 69f0083..2cb31cb 160000 --- a/deps/plotter +++ b/deps/plotter @@ -1 +1 @@ -Subproject commit 69f0083fc07c23d466325e119651b6eb9f85a305 +Subproject commit 2cb31cbb91eefcac0e9479b8b3fb1da487d8288b diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index 4962deb..ce4a89e 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -90,8 +90,8 @@ Every plot shares **one time window**: panning or zooming in any of them moves t sits at the same time in each, and the vertical cursors are the same two times in each. The plots of a split row also share **one y range**: the y labels are drawn at the left of the first plot only, the horizontal rulers are the same two values in every plot, and a y zoom, pan, fit or fixed range in any of -them applies to the whole row. Only the bottom row shows the time -labels. A plot of a split row is named by its row and a letter, `2a` to `2d`: that is what the signals +them applies to the whole row. The time labels sit under the bottom row, and +under any row above it whose columns differ from the row below. A plot of a split row is named by its row and a letter, `2a` to `2d`: that is what the signals page's **Plot on** buttons and the status line call it, and a signal dragged from its badge goes onto the plot under the pointer. The arrangement is saved per source, and a session saved before rows could be split opens with one plot per row, as it was. diff --git a/docs/claude/build-and-run.md b/docs/claude/build-and-run.md index 78799e6..2db2f58 100644 --- a/docs/claude/build-and-run.md +++ b/docs/claude/build-and-run.md @@ -279,8 +279,12 @@ number of *figure rows* (the host's `RowSet::row_count()` is the plot count, `fi rows). `plot(i)`, `link_x()` and the crosshair's hovered index all take the **flattened** plot index. Cell widths use the height scheme: a floor of **64 px logical** per cell, the weights share the rest, the last cell closes the row exactly, and a figure too narrow for the floors shrinks the cells -proportionally and drops the column gap. Only the bottom row's cells carry x labels and the x title -(every other plot gets `XStrip::None`), and the left y gutter stays one maximum over the whole figure. +proportionally and drops the column gap. The x labels and title follow the **column structure**: a row +hides its x strip (`XStrip::None`) only when the row directly below has the *same columns* (same cell +count, same normalised cell weights within 1e-4, empty weights = equal), so `[1][2]/[3][4]` has an axis +under 3 and 4 only while `[1][2]/[3]` has one under 1, 2 and 3; the rule is structural, transitive down a +chain and decided before the measurement pass (`same_columns()` in `figure.cpp`); `set_x_labels_only_on_bottom(false)` +labels every row. The left y gutter stays one maximum over the whole figure. The cells of a figure row can **share one y range**, symmetric to the x link (`docs/superpowers/specs/2026-11-03-split-shared-y-design.md`): @@ -303,6 +307,11 @@ The cells of a figure row can **share one y range**, symmetric to the x link share the rest by the existing `floor + extra * w / total` rule, the floors applying to plot widths. Equal weights give equal plot areas; the first cell's rect is gutter plus its plot width and the rects still tile the row exactly. +- **The right gutter belongs to the last cell.** In a shared-y split row only the last cell gets + `set_right_gutter()`; it is taken off the row beside the y gutter (capped so both fit in half the row + and never beyond the figure's right gutter) and the last cell's rect grows right by it. The gap between + two plot frames is then exactly `col_gap` rather than `col_gap` plus a gutter; unsplit rows and rows + with sharing off lay out as before (`figure_split_row_gap_*`, `figure_row_gutter_without_sharing_is_the_old_layout`). In the GTK4 and GLFW adapters the pointer is routed by **cell rect** (`row_in(rows, x, y)`: the containing cell, else the nearest by squared distance), one `input::Controller` per plot. The tests are diff --git a/docs/claude/invariants-plot-and-layout.md b/docs/claude/invariants-plot-and-layout.md index 1b6be4b..a2e13f3 100644 --- a/docs/claude/invariants-plot-and-layout.md +++ b/docs/claude/invariants-plot-and-layout.md @@ -134,9 +134,16 @@ Part of [CLAUDE.md](../../CLAUDE.md). These are rules that cost a defect to lear per figure row**: `row N` with N the 1-based figure row for a split row, and the 0-based plot index for an unsplit row (the pane read that before splitting existed). Readouts and measurements stay per trace and per plot index; only the axis is shared. - - **Bottom-row x labels only.** The plotter gives every plot that is not in the last figure row - `XStrip::None`; the cells of the bottom row each keep their strip, so a middle-drag on the axis - works in any of them. The `t0` caption goes on those cells too. + - **The x axis is the bottom row's for every run of rows with the same columns.** A figure row gets + `XStrip::None` only if the row directly below has the same columns (same cell count and same + normalised cell weights); a row whose columns differ keeps its own strip under each of its cells + (`[1][2]/[3]` has axes on 1, 2 and 3), because the axis below is at another width and scale. The + rule is structural and transitive, never a function of content. Every cell that carries a strip is + a place a middle-drag on the axis works. The `t0` caption belongs on every cell that carries a strip, + not only the last figure row's. + - **The right gutter is the last cell's.** In a split row with a shared y the plotter gives + `right_gutter` to the last cell alone and takes it off the row like the y gutter, so the visible gap + between two plots is `col_gap` and equal weights give equal axes widths. - **One left gutter, on the first cell only.** The y gutter is one maximum for the whole figure with the same reserved floor as before (`Figure::set_min_y_gutter()`). It is carried by the first cell of each row alone: `Figure::layout` gives every other cell `YStrip::None` from its column index (structurally, diff --git a/help/C/org.udpscope.app/layout.page b/help/C/org.udpscope.app/layout.page index 6da9251..25c48d4 100644 --- a/help/C/org.udpscope.app/layout.page +++ b/help/C/org.udpscope.app/layout.page @@ -59,8 +59,8 @@ panning along time in any of them moves all of them, and the vertical cursors are drawn in every plot. The plots of a split row also share one y range: the y labels are drawn at the left of the first plot only, the horizontal cursors sit at the same values in every plot, and a - zoom, pan, fit or fixed range in any of them applies to the whole row. Only the - bottom row carries the time labels. A row holds at most 4 plots and the figure at most 8 + zoom, pan, fit or fixed range in any of them applies to the whole row. The time labels + sit under the bottom row, and under any row above it whose columns differ from the row below. A row holds at most 4 plots and the figure at most 8 in total; the + buttons go grey at the limit.