Skip to content

First-class TUI: qc view, figures drawn once, squeeze folded into qc, one view rule; version 0.10.9 - #42

Merged
YPARK merged 1 commit into
mainfrom
ypp/trusting-pasteur-ao27p0
Oct 31, 2026
Merged

YPARK merged 1 commit into
mainfrom
ypp/trusting-pasteur-ao27p0

Conversation

@YPARK

@YPARK YPARK commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

The CLI's terminal views become first-class, and its figures are drawn once (modelled on faba). squeeze and plot are folded into specific commands, and everything stays reachable over MCP.

What changes

data-beans qc is its own view on a terminal, modelled on faba qc:

  • Rule table: each cell QC rule with its edge, how many cells it fails, and how many it alone removes.
  • Selected rule: its histogram in three layers: all cells, cells passing the other rules, cells removed only by this rule.
  • Other panels: counts against genes, and the removed cells grouped by the rules they fail.
  • Keys: arrows move a rule along the MAD band, m gives it a value of its own, p shows and c copies the --qc-* flags that decide the same cells, s saves the figure. Enter writes to -o, or asks where (never over the input or an existing file).
  • Exactness: the view edits a QcConfig and reruns qc_lib's own verdict, so the printed flags reproduce it exactly.

Figures (src/figure/, ported from faba): one SVG per figure, written as PDF and PNG.

  • In kitty, iTerm2, WezTerm and Ghostty the views show the figure as an image; other terminals get text plots.
  • qc --figure and stat --figure write them; the MCP qc and statistics tools return them as images.

plot and squeeze are removed.

  • qc --figure and stat --figure replace plot.
  • squeeze's cutoffs are qc's floors: -c is --qc-min-cell-nnz, -r is --qc-feature-min-cells. --qc-auto-cutoff puts both at their troughs, unless --qc-feature-min-cells is given.
  • qc takes several files, pooled as merge-backend merges them (--common-rows), and writes the kept cells' batch labels.
  • The --squeeze flags on the import commands, merge and subset still work through squeeze_in_place.

One log axis for every histogram (qc::axis): printed, view and figure histograms read values on ln(shift + x), with the shift chosen from the data. Means and fractions now spread out instead of piling into the first tenth-decade bins.

One rule decides every view (interactive::opens_view / picks):

  • Batch when asked: --batch-process, on every view command, or DATA_BEANS_BATCH=1 for a whole script.
  • Otherwise a view where stdin and stdout are a terminal and TERM isn't dumb.
  • qc and stat open by default; without a terminal they say so in one stderr line.
  • The pickers (columns, rows, subset*) open only when the command line selects nothing.
  • MCP commands always run in batch.

stdout/stderr: stdout carries only results. QC histograms, notices, logs and errors go to stderr. senna's and pinto's --qc-histogram now prints to stderr.

mcp watch: o on a qc call opens the QC view on the agent's data with its settings; the qc result now names its data as absolute paths.

Version 0.10.9, a patch release: faba's uses of data-beans all still compile. Downstream crates see two behaviour changes: ui::Binning's log bins now use the shared axis, and qc_lib now reads an empty mito or ribo pattern as no metric, where it used to be a regex that found every gene.

Review fixes (from /code-review)

  1. Flags reproduce the view. The mito pattern is always given, empty for off. Under --qc-auto-cutoff so is the gene rule, 0 for off, and qc sets the gene trough only when --qc-feature-min-cells isn't given.
  2. m on a rule with no spread starts from a value that removes nothing, not 0.
  3. --qc-histogram holds after the view. The printed command keeps --backend, --no-zip and --qc-histogram.
  4. Figures are never saved over a file. save refuses, and the views offer the next free name.
  5. The view decides quietly and says when the guardrail keeps every cell. It also notes that the bands are fitted above a genes floor set to a value of its own.
  6. Computed once per change: bands, edges, removed masks and their overlap. The 2R+1 rule variants are decided in parallel, not on every frame.
  7. One place for the band and edge logic: the summary, the figure and the view all read CellRules. The batch summary is unchanged on the test matrix.

Testing

  • Format check, clippy --all-targets --features sim -D warnings, the CI feature matrix (except the HDF5 builds: no libhdf5 here), and cargo test --features sim all pass.
  • New tests cover the rule recount (the printed flags read back through qc's own defaults give the same verdicts, including mito off and a gene rule off under auto cutoff), figures (PDF/PNG, no replacing), the views (TestBackend, the guardrail line), the shared view rule, MCP figures, pooling and qc's data. The PTY session tests now run on qc and stat.
  • Checked by hand on a 800 × 1500 test matrix: the view's numbers match qc (1,380 kept), moving the mito edge writes 1,374, and the printed flags reproduce that.
  • Not tested: image mode in a real kitty or iTerm2 window (only the text mode, through tmux); clipboard copy (c); o in a live watch session; speed at about 1M cells.

@YPARK YPARK changed the title First-class TUI: qc view, figures drawn once, squeeze folded into qc, one view rule; version 0.10.8 First-class TUI: qc view, figures drawn once, squeeze folded into qc, one view rule; version 0.10.9 Oct 31, 2026
@YPARK
YPARK force-pushed the ypp/trusting-pasteur-ao27p0 branch from 36baaf8 to 7b28ac7 Compare October 31, 2026 14:49
… one view rule; version 0.10.9

`data-beans qc` opens a full-screen view on a terminal, modelled on
`faba qc`: each cell QC rule with its edge, how many cells it fails and
how many only it removes; the selected rule's histogram in three layers
(all cells, those passing the other rules, those only it removes);
counts against genes; and the removed cells by the rules they fail. The
view edits a QcConfig and reruns qc_lib's own verdict, so the flags it
prints (`p`) or copies (`c`) decide the same cells. Enter writes to -o,
or asks where, never over the input or an existing file.

- figure: faba's SVG drawing ported in, written as PDF and PNG, drawn as
  terminal images in kitty, iTerm2, WezTerm and Ghostty, text plots
  elsewhere. `qc --figure` and `stat --figure` write the QC and
  statistics figures; the MCP qc and statistics tools return them.
- `plot` and `squeeze` are gone. squeeze's cutoffs are qc's floors (-c
  is --qc-min-cell-nnz, -r --qc-feature-min-cells); --qc-auto-cutoff puts
  both at their troughs unless --qc-feature-min-cells is given. qc takes
  several files, pooled as merge-backend merges them, and writes the kept
  cells' batch labels. The --squeeze flags of the builders, merge and
  subset cut in place through squeeze_in_place.
- One log axis for every histogram (qc::axis, ln(shift + x), the shift
  chosen from the data): printed, view and figure histograms bin on it.
  The stat explorer saves its figure (s) and draws images.
- One rule for every view: batch under --batch-process (on every view
  command) or DATA_BEANS_BATCH=1, else a view where stdin and stdout are
  a terminal and TERM is not dumb. qc and stat open by default; the
  pickers open only when nothing is selected. MCP runs in batch.
- stdout carries only results; QC histograms, notices, logs and errors
  go to stderr.
- `mcp watch`: `o` on a qc call opens the QC view on the agent's data
  with its settings.
- Review fixes: flags reproduce the view (mito off, gene rule under auto
  cutoff); `m` on a rule with no spread removes nothing; --qc-histogram
  holds after the view; figures never replace a file; the view decides
  quietly and says when the guardrail keeps every cell; bands, edges and
  masks are worked out once per change, in parallel; one place for the
  band and edge logic.
@YPARK
YPARK force-pushed the ypp/trusting-pasteur-ao27p0 branch from 7b28ac7 to d97b183 Compare October 31, 2026 14:56
@YPARK
YPARK marked this pull request as ready for review October 31, 2026 14:59
@YPARK
YPARK merged commit 1555fcb into main Oct 31, 2026
5 checks passed
@YPARK
YPARK deleted the ypp/trusting-pasteur-ao27p0 branch October 31, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant