docs: horizontal plot split

This commit is contained in:
Martino Ferrari committed 2026-11-03 19:14:57 +01:00
1 parent 7730b35fe3
commit 2183317953
13 files changed
+319 -39

No files matched your search

+51 -7
View File
@@ -26,8 +26,8 @@ Options: `--server`, `--port`, `--multicast`, `--interface`, `--buffer-samples`
(samples kept per acquired signal, default 10M; see "The sample buffer is budgeted in samples" below),
`--memory-limit-mb` (hard ceiling on the ring storage, default 8192), `--max-window` (largest time
window the toolbar offers, default 600), `--holdoff` (default trigger hold-off),
`--recv-buffer`, `--plots` (the number of stacked plots to start with, 1..8; rows are
added and removed from the **Layout editor** afterwards), `--relative-time` (see below),
`--recv-buffer`, `--plots` (the number of plots to start with, one per row, 1..8; rows are
added and removed and a row can be split into side-by-side plots from the **Layout editor** afterwards), `--relative-time` (see below),
`--source NAME` and the repeatable `--source-opt k=v` (the source kind and its settings; see "Data sources" below),
`--capture-packets N` (see "Packet capture" below), `--renderer NAME` (GTK's renderer:
`cairo`, `gl` or `vulkan`; `cairo` is the software preset that exports both
@@ -1105,6 +1105,9 @@ plots = 1
measure_stats = false
[[plot]]
row = 0
width = 1
weight = 1
signals = ["Ch1", "", "", ""]
[[calibration]]
@@ -1113,6 +1116,14 @@ gain = 2
offset = 0.5
```
Each `[[plot]]` table is one **plot** (one cell of the layout), in left-to-right, top-to-bottom order.
`row` is the figure row the plot sits in (0-based) and `width` its share of that row's width; `weight` is
the *row's* share of the figure's height, written on every plot of the row and read from the row's first
one. A session with no `row` keys -- every file written before a row could be split -- loads as one plot per
row, and so does one whose `row` numbers cannot be a layout (a number that skips or goes back, more than 4
plots in a row or 8 in all): the file is never refused for it, and the signals stay where they were. See
"Splitting a row".
It also stores `measure_stats` (the measurements statistics toggle, a boolean, absent means
`false`) and `dock` (whether the dock is shown, a boolean, absent means `true`; it replaced the
sidebar's `side_tab`, and a file that still carries `side_tab` loads, the key being ignored). The
@@ -2568,7 +2579,8 @@ out of the plot **while a gesture is on that row**, because a drag writes the *p
the only place it is visible. Outside a gesture the plot is not read at all: `cursor.x` is the
snapped value then, which is what the app wrote itself a frame earlier, and adopting that back
is what made a dragged cursor spring to where it had been. A ruler is per row: each row has its own y axis, so two rows' rulers are
two different values, and the pane names the row.
two different values, and the pane names the row. In a split row (see "Splitting a row") the vertical pair is drawn in
every plot and a ruler belongs to one plot, which the pane names `plot 2a`.
`mix` needs no rulers: it reports the value the trace actually has at each marker, read
through the library's `Plot::crosshair_value()` — **the nearer of the two bracketing
@@ -2761,8 +2773,9 @@ full range — the snapshot's own span, which is legitimately *narrower* than th
when the ring had not filled it. A fit of a frozen view keeps it frozen rather than throwing it
back onto the stream.
**Shared x axis.** The rows are the rows of **one `plot::Figure`**, drawn by one
`plot::gtk4::PlotArea` in figure mode, and they all join a single x link group.
**Shared x axis.** The plots are the plots of **one `plot::Figure`** (one per row, or several side by
side in a split row, see "Splitting a row"), drawn by one `plot::gtk4::PlotArea` in figure mode, and they
all join a single x link group.
A gesture changes the row it landed on; `Figure::layout()` adopts that change
into the group and pushes it to the others, so panning or zooming any row moves
them all with nothing to propagate by hand. The live follow is the *group's*
@@ -2776,8 +2789,8 @@ The self-check's layout line carries `x-desync N`, the number of frames in which
any row's x range differed from row 0's by more than a pixel of data. **It must
read 0.**
`Figure`'s row count is fixed at construction, so there is one structural path:
a changed row count, or a changed legend name (the one thing a `Plot` cannot
`Figure`'s shape (its cells per row) is fixed at construction, so there is one structural path:
a changed row or cell count, or a changed legend name (the one thing a `Plot` cannot
express), builds a new figure and the area is handed it. That costs no GL state —
the widget keeps its context. A displayed event survives the rebuild because the
pinned `[-pre, +post]` window is restated rather than re-derived from the live
@@ -2808,6 +2821,37 @@ above row 2" are the same insertion, and two buttons there would sit one on top
other. The `rows + 1` boundary buttons — above the first row and below the last included —
reach every position the two-per-row reading offers.
### Splitting a row
A row can be split into **two to four plots side by side**, up to **eight plots in all**. A split is
only an arrangement of more plots on the screen: **every plot shares the one time window** -- one x
link group, so a pan or zoom in any plot moves them all; one crosshair, drawn at the same time in every
plot; and one pair of vertical cursors, at the same two times in every plot. What each plot keeps is its
own **y axis** (auto or fixed), its own horizontal rulers and its own fit; a wheel or an axis drag acts on
the plot under the pointer. Only the **bottom** row's plots carry the time labels, and the left margin
holding the y labels is one width for the whole figure, so the plots of a row line up with the rows
above and below it; a plot whose labels are narrower simply has more margin.
In the **Layout editor** (`l`):
- A **`+` at a row's left and right edge, and one between each two plots**, splits the row there: a new,
empty plot is added at that position and the plots after it move right *with their traces*. A one-cell
row can be split from either side. The `+` is dim at 4 plots in the row or 8 plots in all (the row `+`,
which adds a whole row, dims at 8 plots).
- A **drag arrow between two plots** resizes the two neighbours against each other; neither can be
dragged below about 96 px. The plotter keeps 64 px as an absolute floor, and when the window is too
narrow for that it shrinks every plot proportionally and drops the gap, so nothing has a negative size.
The widths are saved when the drag ends.
- The **`×`** at a plot's top left removes that plot (and its traces) from a split row, and removes the
*row* from a one-plot row, as it always did. It is dim when that would leave no plot.
Plots are named by their row and, in a split row, a letter: **`1`**, **`2a`**..**`2d`**. The names are
what the signals page's *Plot on* buttons (tooltip "row 2, cell 1 of 2"), the status notices ("plotting
'sine' on plot 2b") and the cursors pane for a split row (`plot 2a`; a plot of an unsplit row stays
`row N`, counted from 0 as before) show. A signal dragged from its badge lands on the plot under the
pointer, with the same free-slot rule as a row. The session file keeps the arrangement (`row` and `width`
on each `[[plot]]`, see "The session layout file").
The buttons are `GtkOverlay` children placed by their margins over the figure's own row
rects (`FigureLayout::rows`, divided by the area's device scale), deliberately **not** one
transparent widget covering the plot: an overlay child is picked wherever its allocation