Analysis parameters
This page is for the person running the experiment, not the person maintaining the code. For each parameter it tables, it answers three questions:
- What is the default, and where does it live? Every row names the constant or field and the module it is defined in, so you can read the value straight out of the source.
- What happens if you change it? Each row states the direction of the trade-off — what you gain and what you lose by raising or lowering the value.
- Can you recover it afterwards? Each row says whether the value you used is written into
the
.tetherproject file, which is what makes a run reproducible and a methods section honest.
Every default on this page was read out of the code, not out of a specification. Where the frozen spec and the code disagree, the code is what ships and the code is what is printed here.
How to read this page
| Column | What it means |
|---|---|
| Parameter | The keyword or field you actually set, and the module its default is defined in. |
| Default | The shipped value. |
| Units | Physical units where they exist. Several parameters are dimensionless fractions or frame counts — the difference matters. |
| Effect on the result | What the parameter controls and which way the trade-off runs. |
| Set via | A real surface: a tether CLI flag, a GUI control, or a documented keyword argument. Where a value is not user-settable this is stated explicitly. |
Recorded in .tether |
The store path where the value you used is persisted, or no if it is not recoverable from the project file. |
Tether has no settings dialog. Ten of the seventeen ExtractOptions fields are exposed as
tether extract flags — --donor-side, --detection-mode, --detection-threshold,
--detection-block, --min-separation, --window, --prealign, --pair-tol, --rms-gate
and --coloc-distance — and for those the command line is the only surface. The other
seven have no flag and no GUI control at all, and are reachable only from Python: the aperture
group (disk_radius, ring_inner, ring_outer,
bg_window) and the prealign group (prealign_upsample, prealign_low_sigma,
prealign_high_sigma). Their rows below say so individually, and all seventeen are recorded
alike — the recording is the same whether the value came from a flag or from Python.
tether batch deliberately exposes none of them: its flags are --tmap,
--tdat, --policy and the sidecar-supervision options, so every movie in a batch is
extracted at the ExtractOptions defaults tabled below unless you drive
run_batch(extract_options=ExtractOptions(...)) from Python — with one exception.
tether batch --tdat applies a shared Deep-LASI detection config to every movie in the run,
and importing one replaces detection_mode and detection_threshold with the values
decoded from the file before the extraction profile is written, exactly as
tether extract --tdat does for a single movie. Under --tdat those two rows below do not
describe your run: read the applied values out of /settings/extraction, where the source
filename is also recorded as tdat_source. Every other extraction parameter is untouched by
--tdat and is still at its default. (--tmap replaces no field, but it does make
donor_side inert — see its row.) Downstream stages
(photobleaching, corrections, idealization, analysis) are driven from Python, so their
"Set via" cells name the keyword argument of the project-level function. Anything with no
surface at all is called out as fixed.
Science tunables vs rendering defaults
Not every default is a scientific choice, and the split below is the one the source itself draws: most constants say which kind they are in their own comment, and this page follows that labelling — with three deliberate promotions, named explicitly below.
- A science tunable changes a reported number. The leakage ceiling, the γ half-window, the bootstrap resample count and the idealization state grid all change what you would publish.
- A rendering default changes only how a distribution is drawn. The histogram bin count, the transition-density grid resolution and the dwell-time histogram bin count are faithful ports of the corresponding tMAVEN display defaults; the raw-FRET cloud and the anticorrelation event finder are Tether's own presentation choices with no tMAVEN counterpart, and the plot-export settings are Tether's own too — not ports of a tMAVEN display default, though tMAVEN does carry a figure size and a savefig format/DPI of its own (Rendering defaults). Changing any of them redraws a plot; it does not change a fitted value.
The three promotions. Under Analysis and histograms, the frame interval (dt / time_dt), the dwell-fit model and CI
level, and the HMM convergence budget (n_iter) are labelled analysis/rendering parameters
in their own source comments, but are tabled here as science tunables, because each of
them changes a number you would report — most sharply the frame interval, which silently
mis-units every published rate.
The distinction is not cosmetic in one direction: halving a bin count will visibly move a peak's apparent position without changing a single fitted state mean. If you are chasing a number, tune the science parameters; if you are chasing a picture, tune the rendering ones. The two groups are tabled separately under Analysis and histograms.
Detection and extraction
Defaults are the fields of ExtractOptions (tether.project.extract), which is the pinned
CLI contract. Fifteen of the seventeen fields pin an explicit value rather than passing
through to whatever the underlying primitive happens to default to; detection_threshold and
min_separation are deliberate None sentinels that defer to each detection mode's own
faithful default (tabled below). All seventeen fields are serialised verbatim into the
profile_json attribute of /settings/extraction on the first extraction into a project;
later movies appended to the same project leave that record untouched, and their
aperture/integration parameters are checked against it rather than re-recorded.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
donor_sidetether.project.extract |
left |
enum left/right |
Which horizontal half of the frame is the donor channel. Getting it backwards swaps donor and acceptor, which inverts every FRET efficiency. Ignored entirely when a Deep-LASI .tmap is imported, because the channels are then split at the map's own crop geometry. |
tether extract --donor-side |
/settings/extraction |
detection_modetether.project.extract |
wavelet |
enum wavelet/intensity/bandpass |
Which particle finder runs. wavelet is an à trous multi-scale detector that is robust to smooth background gradients; intensity and bandpass are Crocker-Grier style band-pass finders driven by a brightness threshold. The choice also changes the default minimum separation (see below), so it moves both which spots are found and how close two of them may sit. |
tether extract --detection-mode; supplied automatically by --tdat |
/settings/extraction |
detection_thresholdtether.project.extract |
None (per-mode: 0.5 intensity, 0.98 bandpass) |
dimensionless fraction of the detection-image maximum | How bright a pixel must be to survive. Raising it finds fewer, brighter molecules; lowering it finds more, at the cost of false positives that later have to be curated out. Under bandpass the value is dual-use — it both floors the image and keeps only the top 1 - threshold fraction of band-pass values — so it bites much harder there than under intensity. Recorded but inert under wavelet. |
tether extract --detection-threshold; supplied automatically by --tdat |
/settings/extraction |
detection_blocktether.project.extract |
50 |
frames | Block size of the moving-average max-projection that the detector runs on. Raising it averages away more blinking and shot noise, but the trailing partial block (the T % block remainder frames) is dropped, so a large block silently discards more of the end of the movie. Lowering it lets single-frame spikes into the per-pixel maximum and shifts which spots are found. Movies shorter than one block fall back to a sum projection. |
tether extract --detection-block |
/settings/extraction |
min_separationtether.project.extract |
None (per-mode: 8.0 wavelet, 3.0 intensity and bandpass) |
px | Non-maximum-suppression radius: two candidates closer than this collapse to one. Raising it merges genuinely distinct molecules and costs recall; lowering it keeps duplicate centroids on a single PSF. Supplying a value overrides the per-mode default for every mode. | tether extract --min-separation |
/settings/extraction |
windowtether.project.extract |
21 |
px, odd | Side length of the aperture and colocalization crop box. It must be odd and must be at least twice ring_outer. Raising it excludes more molecules near the frame edge (their crop no longer fits); lowering it toward the ring diameter is rejected outright. |
tether extract --window |
/settings/extraction |
disk_radiustether.imaging.aperture |
3.0 |
px | Radius of the signal disk that is summed per frame — 29 pixels at the default, on the default 21 px window. Raising it captures more of the PSF tail but admits more shot noise and risks a neighbour's PSF; lowering it clips real signal and depresses both channels. | ExtractOptions(disk_radius=…) or integrate_traces(disk_radius=…) — no CLI flag, no GUI control |
/settings/extraction |
ring_innertether.imaging.aperture |
6.0 |
px | Inner radius of the background annulus. The gap between the disk and this radius is a deliberate dead zone that keeps PSF tail out of the background estimate; shrinking it toward disk_radius lets signal leak into the background and biases the integrated intensity down. |
ExtractOptions(ring_inner=…) or integrate_traces(ring_inner=…) — no CLI flag, no GUI control |
/settings/extraction |
ring_outertether.imaging.aperture |
8.0 |
px | Outer radius of the background annulus — 84 pixels at the defaults. Raising it averages the background over more pixels (a quieter estimate) but reaches further into neighbouring molecules; it also forces a larger window. |
ExtractOptions(ring_outer=…) or integrate_traces(ring_outer=…) — no CLI flag, no GUI control |
/settings/extraction |
bg_windowtether.imaging.aperture |
10 |
frames | Length of the uniform temporal moving average applied to the crop before the ring mean is taken. Raising it produces a smoother background but lags a genuine background change (for example a slow lamp drift); 1 gives the instantaneous per-frame ring mean, which is noisier and pushes that noise straight into every trace. |
ExtractOptions(bg_window=…) or integrate_traces(bg_window=…) — no CLI flag, no GUI control |
/settings/extraction |
Not reachable from the pipeline: ExtractOptions carries no field for the à trous scale count
(n_scales) or scale pair, the MAD multiplier (k), the band-pass lnoise/lobject lengths
(lobject differs per mode — 7 under intensity, 9 under bandpass), the intensity mode's
fine_threshold, the border_margin, or the sub-pixel refinement switch (refine). No CLI
flag, no batch run and no GUI control can change them; they are the faithful Deep-LASI values.
They do remain keyword arguments with those defaults on detect_spots,
detect_spots_intensity and detect_spots_bandpass in tether.imaging.detect if you call a
detector directly — but a value set that way is not what the pipeline runs and is not
recorded in /settings/extraction. Molecule-key quantisation
(MOLECULE_KEY_QUANTUM_PX in tether.imaging.extract) is likewise fixed; it is recorded as
molecule_key_quantum_px in /settings/extraction because a change to it would break
cross-file molecule identity.
Registration and colocalization
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
prealigntether.project.extract |
translation |
enum translation/similarity |
Degrees of freedom of the coarse pre-alignment before control points are paired. The default resolves translation only. similarity adds rotation and isotropic scale via a Fourier-Mellin log-polar pass and is reliable only in the near-identity regime (sub-degree rotation, sub-percent scale). Use it when your two channels are genuinely rotated; it costs time and can mislead on large warps. The prealign never enters the fitted map — it only helps the pairing step find partners. |
tether extract --prealign |
/settings/extraction |
prealign_upsampletether.imaging.register |
10 |
reciprocal px (shift resolved to 1/upsample px) |
Sub-pixel resolution of the phase-correlation shift. Raising it refines the prealign at a compute cost; 1 gives whole-pixel alignment only, which can leave true partners outside pair_tol. |
ExtractOptions(prealign_upsample=…) — no CLI flag, no GUI control |
/settings/extraction |
prealign_low_sigmatether.imaging.register |
3.0 |
px (Gaussian standard deviation) | Low cut of the difference-of-Gaussians band-pass applied before the log-polar pass. Consumed only when prealign is similarity; inert under the default. Raising it strips fine structure the rotation estimate needs. |
ExtractOptions(prealign_low_sigma=…) — no CLI flag, no GUI control |
/settings/extraction |
prealign_high_sigmatether.imaging.register |
20.0 |
px (Gaussian standard deviation) | High cut of the same band-pass; must be strictly greater than the low cut. Inert under the default translation prealign. Raising it lets saturated background into the FFT magnitude and destabilises the estimate. |
ExtractOptions(prealign_high_sigma=…) — no CLI flag, no GUI control |
/settings/extraction |
pair_toltether.imaging.register |
2.0 |
px (Euclidean, inclusive) | Mutual nearest-neighbour gate for accepting a control-point pair. Raising it pairs more points — including spurious ones, which drag the fitted map. Lowering it can leave fewer than the two pairs extraction requires, and the movie fails outright. | tether extract --pair-tol |
/settings/extraction |
rms_gatetether.imaging.calibrate |
0.5 |
px | Residual gate on the fitted channel map. A fit whose RMS residual is strictly above the gate is not rejected: the calibration is flagged low-confidence and every molecule it extracts is tagged, so a marginal registration is visible downstream instead of silently dropped. Raising it hides a bad map; lowering it flags more runs for review. | tether extract --rms-gate |
/settings/extraction |
over-gate policytether.project.batch |
warn |
enum warn/fail |
What a batch run does with an over-gate movie. warn keeps it, flagged; fail fails that movie's stage so it does not enter the pooled analysis. tether extract on a single movie always warns — only the batch runner can fail. |
tether batch --policy |
/settings/batch (policy) |
coloc_distancetether.imaging.coloc |
3.0 |
px (strict <) |
Nearest-neighbour radius for the informational acceptor_detected flag, and nothing else. Tether is donor-anchored: every in-frame donor spot becomes a molecule and its acceptor intensity is read at the mapped position whether or not an acceptor was independently detected there, so changing this value does not add, remove or re-pair a single molecule (tether.imaging.coloc). It is Deep-LASI's findColoc gate, kept as a diagnostic rather than a filter, because filtering on it discards the low-FRET and acceptor-dark population a FRET histogram must keep. A separation of exactly the threshold is not a match. No downstream stage currently consumes the flag. |
tether extract --coloc-distance |
/settings/extraction |
Fixed, not settable: the polynomial map degree and the fallback ladder. Six or more control
points fit a degree-2 polynomial; two to five fall back to a four-degree-of-freedom
similarity; fewer than two is an error. Those thresholds are constants in
tether.imaging.calibrate with no user surface.
Photobleaching and the analysis window
Photobleaching is detected per channel with a Bayesian single-step change-point model, and the default analysis window runs from the start of the trace to the first bleach of the summed donor + acceptor intensity. A window that has already been narrowed by hand is a manual override and is never overwritten by a later detection pass — but note that the only surfaces that narrow it are the tMAVEN return-leg reconcile and a legacy-SMD import, not the curation view (see the row below).
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
intensity_quantitytether.project.photobleach |
corrected |
enum corrected/raw |
Which trace layer the detector runs on. The model treats the post-bleach segment as mean-zero, which only holds once the background pedestal has been removed. Detection tolerates a modest pedestal, but once the pedestal grows to roughly twice the bleach step the trace stops looking bleached at all and the window silently spans the whole movie — which is what running on raw traces risks. |
compute_photobleach(intensity_quantity=…) — no CLI flag, no GUI control |
no |
aPB_PRIOR_A in tether.fret.photobleach |
1.0 |
dimensionless | Shape of the inverse-Gamma prior over the per-segment noise variance. At the default the prior is weak and the data dominate on any trace longer than a few frames. Raising it makes the detector more conservative about calling a small step. | compute_photobleach(a=…) / detect_photobleach(a=…) — no CLI flag, no GUI control |
no |
bPB_PRIOR_B in tether.fret.photobleach |
1.0 |
intensity² (same units as the trace, squared) | Scale of the same inverse-Gamma prior — effectively an assumed noise floor. It enters only as an additive term alongside the trace's summed squared deviations, so it bites only when raised to something comparable with that sum: on a 200-frame trace with a 1000-count step it is inert from 1e-9 up to about 1e6 and suppresses the step only around 1e8. Lowering it below the default has no practical effect — the data term dominates. |
compute_photobleach(b=…) / detect_photobleach(b=…) — no CLI flag, no GUI control |
no |
betaPB_PRIOR_BETA in tether.fret.photobleach |
1.0 |
dimensionless (pseudo-observations) | Precision of the Normal prior over the pre-bleach signal level. At 1.0 the prior contributes about one pseudo-observation at mu, so it barely moves a fit on a trace of tens of frames. Raising it pulls the fitted pre-bleach level toward mu and will bias the change point on short or dim traces. |
compute_photobleach(beta=…) / detect_photobleach(beta=…) — no CLI flag, no GUI control |
no |
muPB_PRIOR_MU in tether.fret.photobleach |
1000.0 |
raw detector counts (ADU) of the background-subtracted trace | Prior mean of the pre-bleach signal level. This is an absolute intensity, not a normalised one, and the asymmetry matters. A level far above mu is harmless. A level far below it is the dangerous case, and it bites at the default beta — no raised beta needed — because the prior's evidence penalty does not shrink as the trace lengthens. Measured on a 200-frame synthetic trace bleaching at frame 100: levels of 1e6 down to 100 counts all recover frame 100, while a level of 10 counts collapses to the all-bleached hypothesis at frame 0. compute_photobleach then reads that as a dark trace — bleach_frames records the start frame and the analysis window is deliberately left at full extent, because a zero-length window is indistinguishable from "unset" downstream. Setting mu to your own single-molecule level restores detection. Lower mu if your traces are dim. |
compute_photobleach(mu=…) / detect_photobleach(mu=…) — no CLI flag, no GUI control |
no |
| analysis window override | auto (start → first bleach of the summed intensity) | frames | The window the windowed readers slice to: the analysis store behind the FRET histograms and cloud, the anticorrelation/cross-correlation scan, the per-molecule engineered features, the per-molecule exports and idealization each cut a trace to it, falling back to frame_range when it is unset. The correction-factor stages do not read it — compute_leakage_alpha, compute_gamma and compute_corrected_fret slice each trace by its native frame_range and locate their tails from the stored bleach_frames, so narrowing the window does not change α, γ or the corrected traces. Because manual bounds win, re-running detection will not restore the automatic one. There is no in-app curation control for the window — the curation view's window keys report that GUI persistence is unavailable and add no data. |
apply_reconcile(accept_windows=…) — the standalone-tMAVEN return leg, surfaced as the GUI reconcile dialog — or import_analysis_only_project from a legacy SMD; auto-set by compute_photobleach only where the window is still at the extraction default |
/molecules (analysis_window, bleach_frames) |
Photobleach detection records none of its own inputs.
tether.project.photobleachwrites the results —bleach_framesandanalysis_window— into/molecules, but it writes no attributes at all: not the priors that produced them, and not the trace layer they were detected on. The layer choice travels only in the transientPhotobleachSummarythe call returns. So if you change any ofa,b,beta,muorintensity_quantity, that choice is not recoverable from the project file, and a reader of your.tethercannot tell a default run from a re-prioritised one, nor acorrectedpass from arawone. Record the values yourself in your methods section, or leave them at the defaults so the defaults on this page describe your run. Every other correction stage stamps its own settings; this one does not.
Correction factors
Leakage α and the detection-correction factor γ are estimated per trace and then pooled to a dataset median. Both estimators are deliberately conservative: a trace that does not qualify contributes nothing, and if too few traces qualify the factor is withheld rather than guessed. Corrections are never required — a project with no usable factors degrades to apparent E rather than producing NaNs.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
intensity_quantity (α and γ)tether.project.leakage / tether.project.gamma |
corrected |
enum corrected/raw |
Which /traces layer the per-trace α and γ are measured from: corrected is the background-subtracted layer, raw the pre-background-subtraction one. Measuring on raw leaves the background in the post-bleach tail means and in the acceptor-drop/donor-rise step heights, so it changes the factors themselves and therefore every corrected E computed from them. Unlike the analysis-side argument of the same name, this choice is stamped, so a reader of your project can tell which layer a factor came from. |
compute_leakage_alpha(intensity_quantity=…), compute_gamma(intensity_quantity=…) — no CLI flag, no GUI control |
/settings/leakage, /settings/gamma |
min_window_frames (α)DEFAULT_MIN_WINDOW_FRAMES in tether.fret.leakage |
20 |
frames | Shortest post-acceptor-bleach tail from which α may be measured. A tail of exactly this length qualifies. Raising it keeps only long, well-averaged tails — fewer contributing traces, a noisier median if you go too far. Lowering it admits short tails whose mean is dominated by shot noise. | compute_leakage_alpha(min_window_frames=…) — no CLI flag, no GUI control |
/settings/leakage |
ceiling (α)LEAKAGE_CEILING in tether.fret.leakage |
0.3 |
dimensionless | A per-trace α outside the inclusive range from zero to the ceiling is rejected as unphysical. Raising it admits traces whose "leakage" is really a mis-detected bleach or a contaminating acceptor; lowering it discards real high-leakage dye pairs and can push the dataset below the qualifying count. | compute_leakage_alpha(ceiling=…) — no CLI flag, no GUI control |
/settings/leakage |
min_qualifying_traces (α)DEFAULT_MIN_QUALIFYING_TRACES in tether.fret.leakage |
10 |
molecules | How many traces must yield an α before the dataset median is trusted. Exactly this many is enough. Below the bar the factor is withheld and the project falls back to apparent E — a deliberate refusal, not a failure. Lowering it lets a median built from a handful of traces correct an entire condition. | compute_leakage_alpha(min_qualifying_traces=…) — no CLI flag, no GUI control |
/settings/leakage |
half_window (γ)DEFAULT_GAMMA_HALF_WINDOW in tether.fret.gamma |
3 |
frames each side of the acceptor-bleach step | How many frames are averaged either side of the step to measure the acceptor drop and the donor rise. Raising it averages away noise but smears a step that is not perfectly sharp, and risks reaching past the donor bleach (the post window is clamped so it cannot). Lowering it makes γ hostage to single-frame noise. | compute_gamma(half_window=…) — no CLI flag, no GUI control |
/settings/gamma |
min_window_frames (γ)DEFAULT_MIN_WINDOW_FRAMES in tether.fret.leakage |
20 |
frames | Both the pre-step FRET segment and the post-step donor-only segment must be strictly longer than this — note the difference from the α gate, which is inclusive. Raising it demands longer stable segments and yields fewer, cleaner γ values. | compute_gamma(min_window_frames=…) — no CLI flag, no GUI control |
/settings/gamma |
ceiling (γ)GAMMA_CEILING in tether.fret.gamma |
5.0 |
dimensionless | A per-trace γ outside the half-open range above zero up to and including the ceiling is rejected. Raising it admits extreme ratios that usually mean the "step" was not a true acceptor-before-donor bleach; lowering it discards genuinely bright-acceptor dye pairs. | compute_gamma(ceiling=…) — no CLI flag, no GUI control |
/settings/gamma |
min_qualifying_traces (γ)DEFAULT_MIN_QUALIFYING_TRACES in tether.fret.leakage |
10 |
molecules | Same contract as for α: below the bar γ is withheld. | compute_gamma(min_qualifying_traces=…) — no CLI flag, no GUI control |
/settings/gamma |
alpha_override / gamma_overridetether.project.correct |
None |
dimensionless | Substitute a factor measured elsewhere — for example on a dedicated donor-only or acceptor-only sample. An override replaces the dataset median for every molecule and is stamped as such, so the corrected traces are labelled manual rather than corrected. |
compute_corrected_fret(alpha_override=…, gamma_override=…) — no CLI flag, no GUI control |
/settings/correction |
apparent_e_onlytether.project.correct |
False |
boolean | Force apparent E even when factors are available. Use it when you distrust the corrections and want the uncorrected quantity on record; the stamp distinguishes a user choice from unavailable corrections. | compute_corrected_fret(apparent_e_only=True) — no CLI flag, no GUI control |
/settings/correction |
Idealization
Idealization runs in an isolated sidecar interpreter. The default model is a variational-Bayes
consensus HMM (vbconhmm — the con is consensus): one global HMM fitted across all of
the project's molecules, not a model per trace. The state count is chosen automatically by
maximising the evidence lower bound over a small grid.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
model_typeMODEL_TYPE_DEFAULT in tether.project.idealize |
vbconhmm |
enum | Which fitter the sidecar runs. Both documented models are population fits, so "pools across traces" is not what separates them: the ebFRET alternative (ebhmm) adds an empirical-Bayes hierarchy — it learns a shared prior across the molecules and keeps per-trace posteriors with per-trace state selection, which makes it more seed-variable and is why it is ratified against its own, looser parity tolerance (see Tolerances and gates). It is a different statistical object, not a tuning knob. Four further keys exist in the sidecar dispatch (vbconhmm_modelselection, ebhmm_modelselection, vbgmm_vbhmm, kmeans_vbhmm) and are accepted but not documented here. |
idealize_molecules(model_type=…) — no CLI flag; the GUI one-click idealize passes whatever it was constructed with |
/idealization/<model> (type) |
nstatestether.project.idealize |
None (automatic) |
count | Leave it unset and the state count is selected by maximum ELBO over the grid; set it and you are forcing K. Forcing a K larger than the data support splits one state into two noise-separated states and inflates your transition counts; forcing it smaller merges states and hides transitions. | idealize_molecules(nstates=…) — no CLI flag |
/idealization/<model> (nstates, nstates_selected_by) |
nstates_gridNSTATES_GRID_DEFAULT in tether.project.idealize |
(1, 2, 3, 4) |
counts | The candidate state counts the automatic selection searches. Widening it lets the ELBO pick a larger K — at the cost of one fit per candidate, so run time scales with the grid. Ties break toward the smaller K. | idealize_molecules(nstates_grid=…) — no CLI flag |
/idealization/<model> (elbo_by_nstates, written when the grid was searched) |
intensity_quantitytether.project.idealize |
corrected |
enum corrected/raw |
Which trace layer is idealized. Fitting raw traces fits the uncorrected FRET, so the state means are not comparable to a corrected run. |
idealize_molecules(intensity_quantity=…) — no CLI flag |
/idealization/<model> (intensity_quantity) |
nrestartstether.project.idealize |
None (tMAVEN's own default) |
restarts per fit | Overrides tMAVEN's modeler.nrestarts preference: how many restarts the variational fitter runs before the best model is kept. Lowering it is faster — its documented use is speeding up tests — and correspondingly more likely to settle in a local optimum. Distinct from max_restarts below, which retries a crashed sidecar and has no effect on the fit. Forwarded to the sidecar but never stamped on the model group. |
idealize_molecules(nrestarts=…) — no CLI flag |
no |
timeoutDEFAULT_SIDECAR_TIMEOUT in tether.idealize.supervisor |
1800.0 |
seconds per idealization call | How long one fit may run before the sidecar is killed. The first fit of a session is dominated by just-in-time compilation and is far slower than the rest, so a short timeout will kill cold runs that would have succeeded. None waits forever. |
tether batch --sidecar-timeout; idealize_molecules(timeout=…) |
no |
max_restartsDEFAULT_MAX_RESTARTS in tether.idealize.supervisor |
3 |
restarts per movie | How many times a transient sidecar failure (a crash or a timeout) is retried — not to be confused with nrestarts, which is a property of the fit itself. A fit error reported by the sidecar itself is never retried. 0 disables restarts, so one transient crash fails that movie. Raising it can turn a systematically broken environment into a very long batch run. |
tether batch --max-restarts |
no |
probe_timeoutDEFAULT_PROBE_TIMEOUT in tether.idealize.supervisor |
120.0 |
seconds | Budget for the one-shot startup liveness probe that decides whether the sidecar environment works at all. Too short on a cold filesystem and a healthy environment is declared unavailable. | SidecarSupervision(probe_timeout=…) — no CLI flag |
no |
defer_if_unavailabletether.idealize.supervisor |
True |
boolean | With the default, a missing sidecar defers idealization for the whole run instead of failing every movie one at a time. Turn it off to make each movie's idealization stage fail in isolation. | tether batch --no-defer |
no |
Analysis and histograms
Science tunables
These change a reported number.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
intensity_quantitythe intensity-layer tether.analysis population functions |
corrected |
enum corrected/raw |
Which trace layer a population statistic is computed on, and the largest single swing in a reported E on this table. corrected selects the background-subtracted layer (/traces/donor_corrected and /traces/acceptor_corrected); raw selects the pre-background-subtraction layer, whose E values are not comparable to a corrected run. The layer name is all corrected means here: every function that takes this argument computes apparent E from the layer it is handed, and nothing under tether.analysis reads /molecules.alpha or /molecules.gamma, so neither setting yields a leakage/γ-corrected efficiency — do not report one as absolute E. Only the views that read a trace layer take it — the 1-D histograms (including the CI band and the per-condition overlay), the 2-D and post-synchronised heatmaps, the cloud views, the cross-correlation and the anticorrelation finder. The four state-path-derived views — population_dwell_times, population_state_number, population_transition_density and population_transition_prob_histogram — have no intensity_quantity argument at all, because their numbers come from the stored state paths and model means rather than from a trace layer. The same argument, with the same default, also exists on compute_leakage_alpha and compute_gamma, where it decides which layer α and γ are measured from and is recorded — see Correction factors. |
population_apparent_e_histogram(intensity_quantity=…), the same argument on the other intensity-layer population functions listed above — no CLI flag, no GUI control |
no |
include_firsttether.analysis.dwell |
False |
boolean | Whether the first dwell of each trace — which is left-censored, because the molecule was already in that state when the window opened — enters the survival fit. The default excludes it. Turning it on biases the fitted lifetime, and is for auditing the censoring, not for reporting. | population_dwell_times(include_first=True) — no CLI flag, no GUI control |
no |
n_resamplesDEFAULT_BOOTSTRAP_RESAMPLES in tether.analysis.histogram |
1000 |
resamples | How many molecule-level bootstrap replicates build the confidence band on a population FRET histogram. Lowering it makes the band a coarser estimate of the true interval. It does not make the band jitter run to run: the resampling is seeded (seed, next row but one), so a band is bit-identical on identical data at any resample count — change the seed and a low-resample band visibly moves. Raising it costs time and buys little once the band has stabilised. |
bootstrap_histogram_ci(n_resamples=…) — no CLI flag, no GUI control |
no (analysis results are computed on demand, not stored) |
ci_levelDEFAULT_CI_LEVEL in tether.analysis.histogram |
0.95 |
probability | Coverage of the percentile interval — the default takes the 2.5th and 97.5th percentiles of the replicate distribution. Raising it widens the band. | bootstrap_histogram_ci(ci_level=…) — no CLI flag, no GUI control |
no |
seedDEFAULT_SEED in tether.analysis.histogram |
0 |
seed | Fixes the resampling so the band is reproducible run to run. Change it only if you want to demonstrate that the band is insensitive to the draw; report the value you used, because a band computed with a different seed is a different band. | bootstrap_histogram_ci(seed=…) — no CLI flag, no GUI control |
no |
per_molecule_equal_weighttether.analysis.histogram |
False |
boolean | With the default, every frame in the population contributes equally, so a long trace counts for more than a short one. Turning it on gives every molecule equal weight, which is the right choice when trace lengths vary systematically between conditions. | population_apparent_e_histogram(per_molecule_equal_weight=True) — no CLI flag, no GUI control |
no |
include_rejectedtether.analysis population functions |
False |
boolean | Whether curator-rejected molecules enter a population statistic. The default excludes them, which is the whole point of curation. Turning it on is for auditing the effect of curation, not for reporting. | population_apparent_e_histogram(include_rejected=True) and the equivalent argument on the other population functions — no CLI flag, no GUI control |
no |
include_stalethe model-derived tether.analysis population functions |
False |
boolean | Whether molecules whose idealization has gone stale enter a model-derived statistic. A molecule is stale when the traces or corrections its state path was fitted on have changed since the fit, so the stored path no longer belongs to the signal underneath it — a re-extraction or a recalibration of α or γ is enough. The default excludes them, which is what keeps a transition-density plot, dwell-time fit, transition-probability histogram or state-number count consistent with the traces it is drawn over. Turning it on mixes a state path with signal it was not fitted on; the fix for a stale cohort is reidealize, not this flag. Only these four functions take it: the 1-D histogram, the raw time-versus-signal 2-D heatmap and the cloud views have no idealization to go stale. Two other model-derived views are exceptions to watch, and neither applies a staleness filter of any kind. The post-synchronised A2 heatmap (population_transition_sync_histogram2d) pairs the persisted Viterbi paths with the current traces but takes no include_stale argument, so it can draw a stale path over signal it was not fitted on. Its one guard compares a state path's extent against the width of the whole /traces array — which is zero-padded to the experiment-max frame count, not trimmed per molecule — so it skips a molecule only when that molecule's idealized extent runs past the shared width. A re-extraction that shortens a single molecule is not caught (the vanished frames are read out of that molecule's zero pad), and neither is a recalibration of α or γ; pass molecule_keys=project.live_idealization_keys(model_name) if you need that view restricted to the live cohort. The A1 model-Gaussian overlay (population_model_gaussian_overlay) is the second: it reads the persisted model's means, variances and populations and draws them over the current histogram with no freshness check at all, and it takes no molecule_keys, so there is no in-call restriction available — check project.live_idealization_keys(model_name) yourself, or reidealize, before trusting an overlay drawn after a re-extraction or a recalibration. |
population_transition_density(include_stale=True), and the same argument on population_dwell_times, population_transition_prob_histogram and population_state_number — no CLI flag, no GUI control |
no |
dt / time_dtDEFAULT_DWELL_DT in tether.analysis.dwell, DEFAULT_TIME_DT in tether.analysis.histogram, DEFAULT_CLOUD_TIME_DT in tether.analysis.cloud |
1.0 |
seconds per frame | Converts frames to physical time. This is the one default that will silently mis-unit a published number. At 1.0 every dwell time is in frames and every fitted rate is per frame, not per second. The frame interval is carried per movie in /movies as frame_time (zero when the source movie declared none), but no analysis function reads it automatically — you must pass it. |
population_dwell_times(dt=…), time_signal_histogram2d(time_dt=…), raw_fret_cloud(time_dt=…) — no CLI flag, no GUI control |
no |
model / ci_level (dwell fits)DEFAULT_DWELL_CI_LEVEL in tether.analysis.dwell |
single, 0.95 |
model name, probability | Which survival form is fitted to the dwell-time distribution and the coverage of the reported parameter intervals. Moving from a single exponential to a double or stretched form changes the reported rate constants, not just the fit quality; choose the model on physical grounds, and report which you used. | population_dwell_times(model=…, ci_level=…) — no CLI flag, no GUI control |
no |
nstatestether.analysis.kinetics |
2 |
count | How many hidden states the shared-parameter Gaussian HMM used for rate-constant estimation is fitted with. Unlike the two rows below, which only govern how the fit terminates, this defines the model. The initialisation is deterministic and derived entirely from K: state means at evenly spaced quantiles of the pooled signal, per-state width scaled as the pooled standard deviation divided by K, a diagonal-dominant transition matrix (0.95 stay probability when K > 1) and a uniform start. Raising K splits one state into two noise-separated states and inflates transition counts; lowering it merges states and hides transitions — the same trade-off as the idealization nstates row above. Because the emissions change, so do the Viterbi paths and every rate constant derived from them. nstates=1 sets the stay probability to 1.0, a model with no transitions at all, so every exit rate degenerates; below 1 it raises ValueError. |
fit_gaussian_hmm(traces, nstates=…) — no CLI flag, no GUI control. The convenience wrapper two_state_rate_constants hardcodes two states and takes no nstates argument, so a non-two-state model means calling fit_gaussian_hmm / viterbi_paths / pooled_exit_rates yourself. |
no |
n_iter / tolDEFAULT_HMM_MAX_ITER, DEFAULT_HMM_TOL in tether.analysis.kinetics |
200, 1e-6 |
iterations, relative log-likelihood change | Convergence budget of the Gaussian HMM used for rate-constant estimation. They run in opposite directions: n_iter is an iteration cap, tol is the stopping threshold on the relative log-likelihood change (EM stops as soon as the absolute change in the total log-likelihood falls to tol·(1 + its magnitude)). Lowering n_iter or raising tol can return an unconverged fit that still looks plausible; raising n_iter or lowering tol costs time only. |
fit_gaussian_hmm(n_iter=…, tol=…) — no CLI flag, no GUI control |
no |
var_floorDEFAULT_HMM_VAR_FLOOR in tether.analysis.kinetics |
1e-6 |
apparent-E units squared (a variance) | Lower bound clamped onto every state's fitted emission variance at each M-step of the same Gaussian HMM. It exists to stop a state that has collapsed onto identical values from producing a zero-width Gaussian and dividing by zero; at the default it sits far below any real FRET noise level and never binds. Because the clamped width feeds straight back into the next E-step, raising it toward your actual noise variance does not merely widen a reported σ — it changes the responsibilities, and so the state assignment and every rate estimated from it. Raise it only to rescue a fit that degenerates, and say so if you do. | fit_gaussian_hmm(var_floor=…) — no CLI flag, no GUI control |
no |
Rendering defaults
These redraw a plot; none of them changes a fitted value. Two rows are less cosmetic than the
rest and say so in place: the transition-sync selection chooses which transitions are drawn
rather than how, and the density switch changes the scale a binned view is returned on. Most
are faithful ports of the
corresponding tMAVEN display defaults and cite the tMAVEN file they came from — the 1-D
histogram (data_hist1d.py), the 2-D and post-synchronised heatmaps (data_hist2d.py), the
transition-density grid (data_tdp.py), the dwell histogram (survival_dwell.py), the
transition-probability view (tm_hist.py) and the state-number bar chart
(model_vbstates.py). The last six rows are Tether's own: the raw-FRET cloud, its k-vs-RMSE
elbow helper, its α-shape support boundary, the donor–acceptor cross-correlation, the
anticorrelation event finder (a QC aid, the pre-idealization counterpart to the HMM's
transition list), and the plot-export settings
(the three formats are a §7.9 requirement; the DPI and figure size are cosmetic output knobs).
None of the six is a port of a tMAVEN display default, but two are not without precedent:
tMAVEN carries its own figure width/height as plot preferences (analysis_plots/base.py) and
its savefig format and DPI as global matplotlib rcParams set by the trace-plot canvas
(trace_plot/multi_plot.py), and it ships
k-means as a modelling routine (modeler/kmeans.py, modeler.run_kmeans). The
cross-correlation is the only one of the six that targets the same quantity as a named tMAVEN
routine, and Tether's is a deliberate divergence rather than a port: tMAVEN's selection.py
heuristic is unnormalized — this is not the raw layer of the science-tunable table above,
it runs on tMAVEN's own corrected data — as well as gradient-based and lag-zero-only. Most, but
not all, carry the rendering-default label in the constant's own comment in
the source: the 1-D histogram bins/range and the plot-export constants do not. Not every value
tabled here has a constant behind it, either: the cross-correlation's two arguments, the
transition-sync selection's three, the density switch, the cloud's time_range and kde, the
elbow's k_min and in_grid_only, the α-shape's alpha and in_grid_only, and the
state-number chart's states_high are plain keyword defaults. Each Parameter cell names the
constant where there is one.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
bins / value_rangeDEFAULT_NBINS, DEFAULT_RANGE in tether.analysis.histogram |
151, (-0.25, 1.25) |
bin count, apparent-E units | Resolution and extent of the one-dimensional FRET histogram. The range is deliberately wider than zero to one so that out-of-range values are visible rather than silently clipped. Fewer bins smooth the distribution and can move a peak's apparent position; more bins expose sampling noise. | apparent_e_histogram(bins=…, value_range=…) — no CLI flag, no GUI control |
no |
densitya keyword default on the binned tether.analysis functions (no module constant) |
True (one-dimensional views), False (two-dimensional views) |
boolean | Whether a binned view is returned as a probability density or as raw (weighted) occupancy counts. At True each bin is divided by its width and by the total in-range mass, so the view integrates to 1 over its range; at False you get the counts themselves. The split is by dimensionality, not by stage: True on the one-dimensional apparent-E histogram, its bootstrap CI band, the per-condition overlay set and the transition-probability histogram; False on the time-versus-signal and post-synchronised two-dimensional heatmaps and on the transition-density plot. The two one-dimensional defaults are faithful tMAVEN ports (data_hist1d.py and tm_hist.py both hard-code density normalisation; Tether makes it a switch), and tMAVEN's two-dimensional views likewise bin raw counts — its hist_normalize / hist_normalizeframe preferences rescale the colour axis and are not this switch. The transform is exact and invertible and moves no peak, so no fitted value changes; but two histograms drawn at different settings are not numerically comparable, and two overlay curves are densities regardless of this switch — the A1 model-Gaussian overlay, which takes no density argument at all, and the transition-probability KDE, which is a gaussian_kde evaluation either way — so drawing either over a density=False histogram puts the two on different scales. The dwell-time histogram is always density-normalised and has no switch at all. |
population_apparent_e_histogram(density=…) and the same keyword on the other binned population functions — no CLI flag, no GUI control (the GUI histogram's y-axis label does follow it: density versus count) |
no |
time_bins / signal_bins / signal_rangeDEFAULT_TIME_BINS, DEFAULT_SIGNAL_BINS, DEFAULT_SIGNAL_RANGE in tether.analysis.histogram |
100, 61, (-0.2, 1.2) |
bin counts, apparent-E units | Grid of the time-versus-signal two-dimensional histogram. These intentionally differ from the one-dimensional defaults above, exactly as in tMAVEN; pass the one-dimensional range if you want a shared E axis across the two plots. | time_signal_histogram2d(…) — no CLI flag, no GUI control |
no |
sync_preframeDEFAULT_SYNC_PREFRAME in tether.analysis.histogram |
50 |
time columns before the transition | Where the selected transition sits on the post-synchronised plot. At half the time-bin count the transition is centred; lower it to show more of the departure, raise it to show more of the approach. | transition_sync_histogram2d(sync_preframe=…) — no CLI flag, no GUI control |
no |
from_state / to_state / single_dwellkeyword defaults on transition_sync_histogram2d in tether.analysis.histogram |
-1, -1, True |
state index, state index, boolean | Which transitions the post-synchronised heatmap is built from, and the shape of the window binned around each. -1 matches any state, so the defaults synchronise on every state jump; setting either to a real state index keeps only transitions leaving from_state and entering to_state (tMAVEN's sync_hmmstate_1 / sync_hmmstate_2, whose own defaults are 0 and -1 — transitions leaving state 0, so Tether's -1 / -1 is a deliberate divergence rather than a port), which changes the n_transitions, n_molecules and n_samples reported with the plot as well as the picture. single_dwell=True is tMAVEN's default window: from the end of the previous dwell to the start of the next, so each transition contributes the one dwell either side; False takes a fixed sync_preframe frames before and time_bins - sync_preframe + 1 after every selected transition, whose overlapping windows may double-count a frame, as in tMAVEN. Not cosmetic in the way the rest of this table is — these choose which events are drawn, not how they are drawn — but no fit is involved, and nothing records which selection you used. |
transition_sync_histogram2d(from_state=…, to_state=…, single_dwell=…) and the same arguments on population_transition_sync_histogram2d — no CLI flag, no GUI control |
no |
nskip / signal_bins / signal_rangeDEFAULT_TDP_NSKIP, DEFAULT_TDP_SIGNAL_BINS, DEFAULT_TDP_SIGNAL_RANGE in tether.analysis.tdp |
2, 101, (-0.25, 1.25) |
frames, bin count per axis, apparent-E units | Grid of the transition-density plot, and how many frames apart the initial and final points of a transition are read so the transition frame itself is skipped. | population_transition_density(…) — no CLI flag, no GUI control |
no |
nbins (dwell histogram)DEFAULT_DWELL_NBINS in tether.analysis.dwell |
51 |
bins | Bin count of the dwell-time distribution view. The survival fit is not binned, so this changes only the picture. | DwellTimeAnalysis.histogram(nbins=…) — no CLI flag, no GUI control |
no |
prob_bins / prob_range / kde_bandwidth / kde_pointsDEFAULT_TPROB_NBINS, DEFAULT_TPROB_RANGE, DEFAULT_TPROB_KDE_BANDWIDTH, DEFAULT_TPROB_KDE_POINTS in tether.analysis.transition_prob |
25, (-0.05, 1.05), 0.25, 100 |
bin count, probability units, bandwidth, grid points | Histogram and kernel-density overlay of per-trace transition probabilities. A wider bandwidth smooths the overlay; it does not change the underlying probabilities. | transition_prob_histogram(…) — no CLI flag, no GUI control |
no |
states_low / states_highDEFAULT_STATE_NUMBER_LOW in tether.analysis.state_number |
1, None (derived from the data) |
state counts (bar-chart x-axis bounds) | Extent of the x-axis of the state-number bar chart, which tallies how many distinct states each molecule's Viterbi path actually occupies. 1 is the natural floor because a molecule with a valid idealization occupies at least one state; states_high at None takes the largest occupied count observed, clamped up to states_low so the axis stays valid on an empty or all-below-floor cohort. Narrowing the axis by hand does not silently drop molecules: the result carries n_molecules, n_in_range and n_out_of_range, so anything outside the bars is still counted and visible. A states_high below states_low is rejected outright. |
population_state_number(states_low=…, states_high=…) — no CLI flag, no GUI control |
no |
cloud grid and contoursDEFAULT_CLOUD_SIGNAL_BINS, DEFAULT_CLOUD_TIME_BINS, DEFAULT_CLOUD_SIGNAL_RANGE, DEFAULT_CLOUD_HDR_COVERAGES, DEFAULT_CLOUD_BW_METHOD in tether.analysis.cloud, plus the time_range and kde keyword defaults there |
100, 100, (-0.25, 1.25), (0.5, 0.95), scott, None (the whole cloud), True |
bin counts, apparent-E units, coverage fractions, rule name, time units (seconds when time_dt is set, frames at its default of 1.0), boolean |
Resolution of the raw-FRET cloud and the highest-density contours drawn on it. The coverages are the contour levels, not a test; the bandwidth rule controls how smooth the density looks. time_range at None spans 0 to the largest pooled time; passing (lo, hi), which must have hi > lo, does more than crop the axis, because the KDE and its HDR levels are fit on the in-grid points only — a narrowed range changes the fitted density, the Scott bandwidth and the reported n_out_of_range count of finite samples excluded from the fit. The same argument on population_fret_cloud_alpha_shape and population_fret_cloud_state_number_elbow selects which points the support boundary is drawn around and which E values are clustered. kde at True computes the density surface and the contour levels; at False the returned density, hdr_levels and bandwidth are all None and only the raw scatter comes back — which is how the α-shape and elbow store wrappers always call it. |
raw_fret_cloud(time_range=…, kde=…), population_raw_fret_cloud(…) — no CLI flag, no GUI control |
no |
| k-vs-RMSE elbow the k_min signature default, DEFAULT_ELBOW_K_MAX, DEFAULT_ELBOW_RESTARTS, DEFAULT_ELBOW_SEED in tether.analysis.cloud, then the in_grid_only signature default |
1, 8, 10, 0, True |
cluster-count floor, cluster-count cap, restarts, seed, boolean | A k-means sweep over pooled apparent-E that hints at a state count. The bare helper k_rmse_elbow takes none of the grid/contour parameters in the previous row — it clusters the E values it is handed. k_min and k_max are the inclusive floor and cap of the probed k range (k_max is further capped at the number of distinct pooled E values); the elbow is the k furthest from the chord joining the curve's two endpoints, so raising k_min above 1 does not merely shorten the curve, it can move the returned elbow_k. More restarts keep the lowest-distortion codebook and steady the RMSE curve; the seed fixes the initialisation. The store-level entry point population_fret_cloud_state_number_elbow pools from a .tether project and does take the cloud's signal_range (defaulting to the same (-0.25, 1.25) as the previous row), time_range and time_dt: at the default in_grid_only=True only samples inside that range are clustered, so an off-grid bleach or blink excursion cannot raise a spurious extra E band; in_grid_only=False clusters the whole scatter. At the default time_range=None the time span is the whole cloud, so it is the E range and not the time range that does the filtering. It is a pre-idealization hint, not a determination — the state count of record comes from the model view. |
k_rmse_elbow(k_min=…, k_max=…, restarts=…, seed=…), population_fret_cloud_state_number_elbow(k_min=…, in_grid_only=…) — no CLI flag, no GUI control |
no |
α-shape support boundaryDEFAULT_ALPHA_FACTOR in tether.analysis.cloud, and the alpha / in_grid_only keyword defaults there |
2.0, None, True |
multiplier, dimensionless circumradius threshold, boolean | The concave support boundary drawn around the raw-FRET cloud, and the time·E support area reported with it. alpha is a circumradius cut applied after each axis is rescaled to [0, 1] over the cloud's bounding box, so it is dimensionless and comparable across the time and E scales; at None it resolves to DEFAULT_ALPHA_FACTOR times the median finite triangle circumradius, which adapts to the cloud's own density. Raising it keeps more Delaunay triangles, so the boundary relaxes toward the convex hull and the reported area grows; lowering it drops the gap-spanning slivers for a more concave shape, until no triangle survives and an empty boundary is returned rather than a fabricated one. in_grid_only is on the two population_fret_cloud_* entry points only, not on alpha_shape itself: at the default just the points inside the cloud's time_range × signal_range — the same window the density surface is drawn on — bound the shape, so a finite but off-grid bleach/blink outlier stays in the honest scatter without dragging the boundary out to meet it; False bounds the full scatter. Nothing downstream consumes the boundary — it is a QC visualization, not a factor in any fitted value. |
population_fret_cloud_alpha_shape(alpha=…, in_grid_only=…), alpha_shape(points, alpha=…) — no CLI flag, no GUI control |
no — but the returned AlphaShape.alpha reports the threshold actually applied, including the auto-selected one |
cross-correlation lag axismax_lag, normalize keyword defaults in tether.analysis.crosscorr |
None (the full axis), pearson |
frames, normalisation name | Extent of the donor–acceptor cross-correlation curve. At the default the curve spans every lag the data supports: ±(N − 1) frames for one trace, and for a population the shortest usable molecule's ±(N − 1). Passing max_lag truncates that axis after the full FFT, so it neither saves work nor moves the values that remain — the reported lag0 and lag1_magnitude are unchanged, with the one exception that max_lag=0 drops lag +1 and leaves lag1_magnitude as NaN. normalize is not a choice: "pearson" is the only value accepted and anything else raises, so no run can quietly use a different normalisation. The intensity_quantity and include_rejected arguments behave exactly as in their rows above. |
population_cross_correlation(max_lag=…), cross_correlation(max_lag=…) — no CLI flag, no GUI control |
no |
anticorrelation event finderDEFAULT_ANTICORR_WINDOW, DEFAULT_ANTICORR_STEP, DEFAULT_ANTICORR_MIN_MAGNITUDE, DEFAULT_ANTICORR_MIN_WINDOWS in tether.analysis.anticorrelation |
15, 1, 0.5, 1 |
frames, frames, correlation magnitude, consecutive windows | Tether's own sliding-window quality-control flagger for anti-phase donor/acceptor behaviour — there is no tMAVEN counterpart. The 0.5 magnitude cut is the classical "clear correlation" threshold, chosen to reject white same-frame shot-noise anticorrelation. Nothing downstream consumes the events, so tuning these changes only what is highlighted for your attention: raise the magnitude or the window count to suppress marginal flags. |
population_anticorrelation_events(…) — no CLI flag, no GUI control |
no |
plot exportDEFAULT_EXPORT_DPI, DEFAULT_FIGSIZE, DEFAULT_PLOT_FORMATS in tether.analysis.plot_export |
200, (6.4, 4.8), ("pdf", "svg", "png") |
dots per inch, inches, formats | Resolution, size and file formats of exported figures. The raster resolution is ignored by the two vector formats. The three formats are a §7.9 requirement rather than a preference; the DPI and figure size are cosmetic output knobs. Purely presentational. | export_figure(dpi=…, formats=…) and the render_* functions' figsize= — no CLI flag, no GUI control |
no |
Curation ranker
The quality ranker orders molecules for review. It never drops a molecule: ranking changes the order you see them in, not the population that enters an analysis.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
intensity_quantity / include_rejectedcompute_features in tether.project.features |
corrected, True |
enum corrected/raw, boolean |
Which trace layer the cached /features/table is computed on, and which molecules get a row in it. The ranker is trained and scored on that table (ranking_dataset reads it), so both settings propagate into every ranking: changing the layer changes all seven trace-derived features, and a molecule with no row cannot be ranked at all. The two spatial features (neighbor_distance, aperture_overlap) are computed from /molecules coordinates and are unaffected by the layer. include_rejected defaults the opposite way here to everywhere else on this page: feature generation keeps rejected molecules by design, because a reject is the ranker's negative training label, whereas the tether.analysis population functions exclude them. Recompute the table after a re-extraction or a recalibration — it is a derived cache, not a record. |
compute_features(intensity_quantity=…, include_rejected=…) — no CLI flag, no GUI control |
intensity_quantity yes, as the /features/table attribute of the same name; include_rejected no |
w0DEFAULT_SEED_WEIGHT in tether.ml.weighting |
0.3 |
relative weight | Weight of a provisional seed label relative to a human one, which is fixed at 1.0. Seed weight decays as human labels accumulate, so the model leans on the seed only while you have labelled little. Raising it makes a cold-start model trust its own priors longer; lowering it makes early rankings closer to random until you have labelled enough. |
train_ranker(w0=…), recompute_label_weights(w0=…) — no CLI flag, no GUI control |
depends on the surface. train_ranker is read-only: it derives the decayed weights in memory for the fit and writes nothing, so a non-default w0 training run leaves no trace in the project. recompute_label_weights is the store-mutating one — it rewrites the resulting per-label weight values into /labels/table. Even then w0 itself is not stamped |
learning_rateRankerHyperparams in tether.ml.gbranker |
0.1 |
dimensionless | Gradient-boosting shrinkage. Lower learns more slowly and needs more iterations; higher can overfit a small label set. | train_quality_ranker(hyperparams=…), ranker_prequential_uplift(hyperparams=…) — no CLI flag, no GUI control |
no, and neither surface named to the left writes the value anywhere else: train_quality_ranker returns an in-memory QualityRanker, and ranker_prequential_uplift is read-only and persists no model. A manifest.json carrying the hyper-parameters exists only on the separate portable-model path — train_portable_model or warm_start_retrain in tether.ml.persistence, written out by save_model — so unless you took that path, a non-default hyperparams is recoverable only from your own notes |
max_iterRankerHyperparams in tether.ml.gbranker |
100 |
boosting iterations | Number of trees. More capacity, more overfitting risk on the modest label sets this ranker is built for. | as above | no — as above |
max_leaf_nodesRankerHyperparams in tether.ml.gbranker |
15 |
leaves per tree | Tree capacity, deliberately below the library default because a curator's label set is small. Raising it lets the model carve finer distinctions and memorise noise. | as above | no — as above |
min_samples_leafRankerHyperparams in tether.ml.gbranker |
5 |
labelled molecules | Minimum labels behind any leaf, again lowered from the library default so the model can split on modest label sets. Raising it makes the model refuse to split until you have labelled more. | as above | no — as above |
l2_regularizationRankerHyperparams in tether.ml.gbranker |
1.0 |
dimensionless | Guards against overfitting a small sample. | as above | no — as above |
early_stoppingRankerHyperparams in tether.ml.gbranker |
False |
boolean | Off by design: enabling it would carve an internal validation split out of an already small label set and make the fit depend on that split. | as above | no — as above |
random_stateRankerHyperparams in tether.ml.gbranker |
0 |
seed | Fixes the histogram-binning subsample so a ranking is reproducible. | as above | no — as above |
alpha (drift advisory)DEFAULT_DRIFT_ALPHA in tether.ml.drift |
0.05 |
family-wise probability | Family-wise significance for the per-feature two-sample test that warns when a model trained on one condition is being applied to a visibly different one. It is Bonferroni-corrected across the features actually tested, and the report is advisory — nothing is blocked. Raising it produces more warnings. | cross_condition_drift(alpha=…) — no CLI flag, no GUI control |
no |
ship_bar_ptsDEFAULT_SHIP_BAR_PTS in tether.ml.prequential |
10.0 |
percentage points of precision-at-k | The uplift over file order, median across videos, at which the prequential evaluation calls the ranker worth using. It is a reporting threshold on an evaluation, not something that changes a ranking. | ranker_prequential_uplift(ship_bar_pts=…) — no CLI flag, no GUI control |
no |
Deep trace classifier
The optional GPU add-on has its own defaults; see
Deep trace classifier (optional GPU add-on) for setup and usage.
None of them affect the base application, and none are recorded in .tether — a trained deep
model is a separate artifact.
| Parameter | Default | Units | Effect on the result | Set via | Recorded in .tether |
|---|---|---|---|---|---|
intensity_quantitytether.project.deep_dataset |
corrected |
enum corrected/raw |
Which /traces layer supplies the model input. corrected selects the background-subtracted layer (/traces/donor_corrected and /traces/acceptor_corrected); raw selects the pre-background-subtraction layer. This is chosen independently of the layer the engineered features were computed on — the labels and weights are per-molecule and layer-independent. Training on raw changes the model input as much as dropping a channel does, and the per-trace scaling does not undo it: per_trace_total divides both channels by a single shared number, which rescales an additive background pedestal but never removes it, so on raw the pedestal survives into the tensor and inflates the divisor. A model trained on one layer cannot score a dataset built on the other — predict_proba refuses. Only build_deep_dataset reads a layer; assemble_dataset accepts the same argument as a provenance label only, since the caller supplies the arrays. |
build_deep_dataset(intensity_quantity=…) — no CLI flag, no GUI control |
no — stamped on the returned TrainedDeepClassifier, which predict_proba and fine_tune both check before scoring or adapting |
channelsDEFAULT_DEEP_CHANNELS in tether.ml.deep.dataset |
("donor", "acceptor") |
channel names | Which measured channels are stacked, in order, as the model input. The tuple is axis 1 of the tensor and therefore the input channel count of the first convolution, so a donor-only or acceptor-only set trains a different classifier on strictly less of the trace. Only a non-empty, duplicate-free subset of ("donor", "acceptor") is accepted. Dropping a channel does not change the scaling: the shared per-trace scale is still computed from donor plus acceptor. |
build_deep_dataset(channels=…) or assemble_dataset(channels=…) — no CLI flag, no GUI control |
no — stamped on the returned TrainedDeepClassifier, which predict_proba checks before scoring |
window_lengthDEFAULT_WINDOW_LENGTH in tether.ml.deep.dataset |
500 |
frames | Fixed length every trace is cropped or zero-padded to. Shorter windows discard the tail of long traces — real data thrown away. Longer ones only cost compute: a boolean mask marks the real frames, the convolutional stack is length-preserving, and the LSTM is packed against the per-trace valid lengths, so padded frames never reach the recurrent summary or the classification head. | assemble_dataset(window_length=…) — no CLI flag, no GUI control |
no |
normalizationDEFAULT_NORMALIZATION in tether.ml.deep.dataset |
per_trace_total |
enum | Per-trace scaling of the two channels by their combined total, which preserves the donor/acceptor ratio while removing absolute brightness. none keeps absolute counts, which makes the model sensitive to gain and exposure. |
assemble_dataset(normalization=…) — no CLI flag, no GUI control |
no |
val_fraction / split_seed / stratifyDEFAULT_VAL_FRACTION, DEFAULT_SPLIT_SEED in tether.ml.deep.dataset; stratify is a keyword default there, with no constant behind it |
0.2, 0, True |
fraction, seed, boolean | Size, reproducibility and class balance of the held-out split only — the same DEFAULT_SPLIT_SEED constant also supplies the training seed, which is a different job; see the training seed row below. A smaller validation fraction leaves more data for training and a noisier estimate of how well it worked. At the default the split is drawn within each label class, so the accept/reject ratio is preserved on both sides and a class of two or more rows never empties out of either side. stratify=False draws the validation rows from one global pool instead, so the held-out class balance is free to drift away from the training one — a held-out score reported from a non-stratified split is not comparable with one from the default. |
train_val_split(val_fraction=…, seed=…, stratify=…), DeepTraceDataset.split(…) — no CLI flag, no GUI control |
no |
epochs / batch_size / learning_rateDEFAULT_EPOCHS, DEFAULT_BATCH_SIZE, DEFAULT_LEARNING_RATE in tether.ml.deep.model |
20, 32, 0.001 |
epochs, traces, dimensionless | Training budget. Too few epochs underfits; too many overfits a small label set with no early stopping to catch it. | train_classifier(…) and fine_tune(…), which take the same batch_size default; predict_proba(…) and rank_by_deep_model(…) take it too, but there it only chunks the scoring pass — no CLI flag, no GUI control |
no |
training seedDEFAULT_SPLIT_SEED in tether.ml.deep.dataset, reused as the signature default of train_classifier and fine_tune in tether.ml.deep.model |
0 |
seed | The training RNG — the same constant as the split seed two rows up, but a different job. It is passed to torch.manual_seed before the weights are initialised and it seeds the DataLoader shuffle generator, so two runs that differ only in seed produce different trained classifiers and different per-trace scores. Report the seed you trained at. The source claims determinism for a fixed seed on CPU; a CUDA run is not promised to be bit-reproducible. |
train_classifier(seed=…), fine_tune(seed=…) — no CLI flag, no GUI control |
no — stamped as seed in the returned TrainedDeepClassifier's hyperparameters |
num_conv_layers / conv_channels / kernel_size / lstm_hidden / bidirectional / dropoutDEFAULT_NUM_CONV_LAYERS, DEFAULT_CONV_CHANNELS, DEFAULT_KERNEL_SIZE, DEFAULT_LSTM_HIDDEN, DEFAULT_BIDIRECTIONAL, DEFAULT_DROPOUT in tether.ml.deep.model |
2, 32, 5, 32, True, 0.0 |
layers, channels, frames, units, boolean, probability | Network shape. Larger capacity fits more complex trace morphologies and overfits sooner; dropout above zero trades training fit for generalisation. | train_classifier(…) — no CLI flag, no GUI control |
no |
fine-tuning epochs / learning_rate / freeze_convDEFAULT_FINE_TUNE_EPOCHS, DEFAULT_FINE_TUNE_LEARNING_RATE, DEFAULT_FREEZE_CONV in tether.ml.deep.model |
10, 0.0001, False |
epochs, dimensionless, boolean | Transfer of a trained model to a new condition. The low fine-tuning rate is what keeps the transferred model from forgetting the source condition; freezing the convolutional stack restricts adaptation to the recurrent head, which helps when the new condition has very few labels. fine_tune also takes batch_size, at the training default of 32 — it is stamped into the fine-tuned model's hyperparameters alongside the fine-tune values, so report it if you changed it. |
fine_tune(…) — no CLI flag, no GUI control |
no |
deviceDEFAULT_DEVICE in tether.ml.deep.model |
cpu on train_classifier; None on fine_tune and predict_proba |
device string | Where training runs. Not a scientific parameter, but it is the one you will change first. The cpu default is train_classifier's. fine_tune and predict_proba take device=None instead and resolve it from the model they are handed — fine_tune from base.hyperparameters['device'], predict_proba from the trained classifier's — falling back to DEFAULT_DEVICE when the model records no device, which is also what a bare nn.Module handed to predict_proba gets. So a classifier trained on CUDA fine-tunes and scores on CUDA unless you pass device yourself; rank_by_deep_model takes no device argument at all and always inherits. |
train_classifier(device=…), fine_tune(device=…), predict_proba(device=…) — no CLI flag, no GUI control |
no — but the device actually used is stamped as device in the returned TrainedDeepClassifier's hyperparameters, which is the record the fine-tune and scoring paths inherit from |
Tolerances and gates
Some numbers in Tether are not really knobs: they are acceptance thresholds that decide whether a result is trustworthy. Their values are deliberately not restated here, because the evidence that justifies each one lives with the decision record that set it, and a second copy would drift. Use this section to find the authority for each, then read the value from there. Where one of them is settable per call, the row says so.
For the gates that were measured rather than chosen, Validation & benchmarks carries the evidence: the frozen numbers, what produced them, and — stated explicitly — which direction of change CI does and does not catch.
| Gate | Where the value lives | What it decides |
|---|---|---|
| Registration RMS residual | DEFAULT_RMS_GATE_PX in tether.imaging.calibrate; rationale in ADR-0014 |
Whether a channel map is flagged low-confidence, and — under tether batch --policy fail — whether the movie is failed. Settable as --rms-gate; the policy is the gate. |
| Leakage α acceptance range | LEAKAGE_CEILING in tether.fret.leakage; estimator rationale in ADR-0027 |
Which per-trace α values enter the dataset median. |
| γ acceptance range | GAMMA_CEILING in tether.fret.gamma; estimator rationale in ADR-0028 |
Which per-trace γ values enter the dataset median. |
| Idealization parity tolerance | schema/parity_tolerance.json, loaded by load_frozen_tolerance in tether.idealize.parity; rationale in ADR-0009 and ADR-0043; measured spreads and re-freeze recipe in Validation & benchmarks |
Whether Tether's idealization is accepted as matching the reference implementation. The file carries a per-method row: the empirical-Bayes model is ratified against its own, looser tolerance, not the default one. Read the method's own row, not the top-level one. |
| Bleach-frame agreement | asserted directly in tests/test_fret_photobleach.py |
How closely the detector must recover a known bleach frame. It exists only as a test assertion — there is no module constant, and therefore nothing to set. |
| Photobleach window default | rationale in ADR-0026 | How the automatic analysis window is derived and why a manual window always wins. |
| Per-trace interaction budget | PER_TRACE_LATENCY_BUDGET_S in tether.project.perf |
A performance budget, not a scientific one: how long one molecule may take to render and advance. |
| Lock staleness | DEFAULT_STALENESS_TIMEOUT_S in tether.project.lock |
When another process's write lock on a project is treated as abandoned. Unlike the other rows here it is settable per call — Project.acquire_lock(timeout_s=…) and Project.write_lock(timeout_s=…) both accept it — but the value you used is not persisted. |
| Return-leg identity match | DEFAULT_MATCH_ATOL / DEFAULT_MATCH_RTOL in tether.project.handoff; rationale in ADR-0025 |
Which traces coming back from standalone tMAVEN are recognised as the store molecules they left as, and therefore whether an accepted window edit, class change or imported model reaches them at all — an unrecognised trace is reported unmatched and dropped, never mis-attributed. It is an equality guard rather than a tunable: tMAVEN preserves the SMD raw array unchanged across a save, so the correct test is equality with a float guard. Like the row above it is settable per call, but only on the module-level tether.project.handoff.read_return_leg / apply_reconcile — the same-named Project methods and the GUI reconcile dialog do not forward it, and no CLI flag exposes it. |
Recording parameters in a methods section
If you ran everything at the defaults, this page describes your run and you can cite it. If you changed anything, what you can recover afterwards depends on the stage:
- Extraction and registration — fully recoverable for the one-movie project
tether extractandtether batchproduce. Read/settings/extraction: the aperture and integration parameters are attributes, and theprofile_jsonattribute holds every field ofExtractOptionsas it was applied. The two Deep-LASI legacy-import paths —reconstruct_projectandimport_analysis_only_project, the two legs the GUI's Deep-LASI wizard drives — are not that, and neither ever had anExtractOptions. A reconstruction writes the group, but its five aperture and integration attributes are fixed module constants describing the provenance of the pre-integrated legacy traces rather than an integration the import performed, andprofile_jsonholds a short provenance dict instead. An analysis-only import (a coordinate-less SMD or.txt, no movie) writes no/settings/extractiongroup at all. The group is stamped by the first extraction into a project and never rewritten, and a later movie is only checked for consistency onwindow,disk_radius,ring_inner,ring_outerandbg_window. So if you appended several movies into one project from Python (write_extraction— no CLI or GUI command does this),/settings/extractiondescribes the first movie only: a later movie'sdetection_mode,prealign,pair_tol,rms_gateorcoloc_distanceis neither rejected nor recorded, and you must state those yourself. - Batch policy — recoverable from
/settings/batch. The sidecar supervision settings (timeout, restarts) are not recorded. A batch run has no extraction flags, so its/settings/extractionis the shippedExtractOptionsdefaults unless the run was driven from Python with an explicitextract_options— or--tdatwas passed, which replaces the detection mode and threshold for every movie in the run. That case is still fully recoverable:/settings/extractionholds the values actually applied and names the file they came from intdat_source. - Corrections — fully recoverable.
/settings/leakageand/settings/gammarecord the window, ceiling and qualifying-count thresholds actually used, along with the resulting factor and how many molecules qualified;/settings/correctionrecords any overrides and whether apparent E was forced. - Idealization — the model type, the selected state count and how it was selected are
recorded on the
/idealization/<model>group, together with the per-K evidence whenever the state count was chosen automatically. The sidecar timeout and restart budget are not, and neither isnrestarts— if you overrode the fitter's restart count, write it down. - Photobleaching — the results are recorded, the inputs are not: neither the priors nor
the
intensity_quantitytrace layer detection ran on. If you changed either, write it down yourself. - Analysis — nothing is recorded, because analysis outputs are computed on demand rather
than stored. Any bin count, bootstrap setting, trace layer or frame interval you passed must
be stated in your methods section. The frame interval is the one to check first: at the
default, dwell times and rates come out per frame, not per second. State the
intensity_quantitytoo — a histogram computed onrawtraces is not comparable to one computed oncorrected, and nothing in the project file records which you used. - Curation ranking — the trace layer the cached feature table was built on is recoverable,
as the
intensity_quantityattribute of/features/table. Whether rejected molecules were featured is not, and neither are the ranker's own hyper-parameters. They are written down only if you took the separate portable-model path —train_portable_modelorwarm_start_retrain, saved withsave_model— which stamps them into the artifact'smanifest.json. The two surfaces that accept ahyperparamsoverride,train_quality_rankerandranker_prequential_uplift, produce no artifact at all, and the project-leveltrain_rankertakes no override and always fits atDEFAULT_HYPERPARAMS. So a non-default hyper-parameter outside the portable-model path has to be stated in your methods section.