Skip to content

Viewer's calibration Apply writes a uniform RT tolerance where a real search uses a position-dependent one #83

Description

@jspaezp

The calibration panel's Apply button writes a single RtTolerance::Minutes into the viewer's query tolerance. Phase 3 of a real search does not use a uniform window: CalibrationResult::get_tolerance (rust/timsseek/src/rt_calibration.rs:209-222) interpolates the measured ridge half-width at each query's own library RT (ridge_half_width_interp, :447-465) and falls back to a uniform scalar only where the ridge has no measurement there. Call site: rust/timsseek/src/scoring/pipeline.rs:570-576.

So a chromatogram the viewer extracts after clicking Apply is not the chromatogram the search extracts for that peptide.

There are two separate mismatches.

1. Uniform vs per-position. rust/timsquery_viewer/src/calibration.rs:1087-1090 applies one number to every peptide.

2. The scalar is the wrong scalar. The viewer's number is the Σ-weighted mean ridge half-width (calibration.rs:1033-1041, floored at 0.5 min at :1071). Production's fallback scalar is rt_sigma_factor * 1.4826 * MAD(rt residuals about the fitted curve) / 60, floored by min_rt_tolerance_minutes (rust/timsseek_cli/src/processing.rs:1046-1049; defaults 3.0 / 0.5 in rust/timsseek_cli/assets/default_config.toml:62-71). The weighted-mean ridge width is only a diagnostic in production (processing.rs:934-953, rt_calibration.rs:233-267) — calib_dash labels it as such (rust/calib_dash/src/app.rs, the ToleranceSummary::rt_seconds doc).

Reproduction

Load a raw file plus speclib, run calibration to Done, click Apply, then select any peptide whose ridge half-width differs from the weighted mean. The panel prints min/max, so any run where those differ by more than ~2× will do. The extracted chromatogram window equals ±weighted_mean, whereas a timsseek search of the same peptide extracts ±ridge_half_width_interp(library_rt).

Expected

The extraction window the viewer uses for a peptide equals the one Phase 3 would use for that peptide: the ridge half-width interpolated at that peptide's library RT, floored at MIN_RT_TOLERANCE_MINUTES, falling back to the MAD-derived scalar only where the ridge has no measurement.

Actual

One uniform window for every peptide, derived by a formula production uses only for reporting.

Notes for whoever picks this up

  • RtTolerance has no position-dependent variant (rust/timsquery/src/models/tolerance.rs:55-62), and data.tolerance is user-editable (rust/timsquery_viewer/src/ui/tolerance_editor.rs:74-123) and persisted (app.rs:334, 1403). The per-query window therefore has to be applied where the query is built (app.rs:527-545), not stored in the editor field. Suggested shape: keep Apply writing the (corrected) fallback scalar so the editor never lies, and add an explicit "use per-query ridge window" toggle.
  • The chromatogram cache key is (selected_idx, data.tolerance, smoothing) (computed_state.rs:246-258; callers app.rs:473, 583, 675, 726). It must see the effective tolerance, or a live re-fit that moves the ridge will serve a stale chromatogram.
  • MIN_RT_TOLERANCE_MINUTES (rt_calibration.rs:36) is private and already duplicated as a bare 0.5 at calibration.rs:1071. Make it pub rather than spelling it a third time.
  • calibration.rs has no tests today. Extracting an effective_tolerance(idx) helper out of generate_chromatogram is what makes this testable — the rest of that method is 130 lines of egui and thread spawning.

Estimated cost: ~76 lines across three files including the cache-key fix, plus ~45 lines of tests once the helper is extracted.


Found while auditing the new RT-calibration dashboard (calib_dash) against the viewer's analogous panel. Two related bugs in the same file are being fixed separately, since they are near-line-neutral and unit-testable: the grid axes being derived from the acquisition RT range rather than from the calibrant points, and the reload path weighing calibrants by score.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions