Usage: CLI
twb cli is a command-line app for preprocessing, repeated-event grouping, deduplication, labeling, and filtering of Twitcher CSV files.
See Installation and Reference/annotation data pages for the instructions to install the app and obtain and arrange the reference genome and annotation data.
The current dedup_cli.py (the module twb cli runs) supports three main modes:
- Full post-processing mode — enrich raw Twitcher CSV files using the same backend pipeline as the web viewer, including configurable repeated-event handling.
- Dedup-only mode — run the lightweight historical exact-column deduplication utility.
- Filter-only mode — apply web-style filters, exported web filter presets, raw filter JSON, or inline CLI filters to an already processed CSV.
Full preprocessing supports three repeated-event modes: group (default), collapse, and off. These modes are separate from the legacy --dedup-only utility.
twb is registered as a console script in pyproject.toml:
[project.scripts]
twb = "backend.cli:main"Contents
- Running
twb cliunder different platforms - Available command-line parameters
- CLI: inspect available columns
- CLI: full post-processing mode
- CLI: label
sample_namevalues - CLI: repeated-event group filters
- CLI: filter-only mode — includes the full list of supported filter operators (string, numeric, region, CIGAR)
- CLI: advanced query filtering
- CLI: filter reports
- CLI: dedup-only mode
- CLI: report-only mode
- CLI: efficiency tips
Running twb cli under different platforms
Singularity
Pull and convert the image:
singularity pull twb.sif docker://aryashta/twb:latestTest that the image works:
ref=./relative/path/to/hg38.no_alt.fa.gz
singularity exec -B $PWD:$PWD twb.sif twb cli -r $ref -o output.csv input.csv Tip! It may be convenient to write a wrapper for the Singularity call and thus avoid writing a long command every time. That can be done by going to the directory of the twb.sif file and executing the commands:
cat > twb-cli << EOF
#!/bin/bash
singularity exec -B \$PWD:\$PWD $(realpath twb.sif) twb cli \$*
EOF
chmod +x twb-cliThe resulting wrapper file twb-cli can now be moved to somewhere on the execution path (e.g. to /usr/local/bin/) and then called directly:
twb-cli -r $ref -o output.csv input.csv Note that the file system mapping used in the wrapper only exposes the current working directory and its subdirectories for the TWB container. If you get “File not found” error, check that the files are real files and not links to somewhere else in the file system.
Docker
Pull and tag the image:
docker pull aryashta/twb:latest
docker tag aryashta/twb:latest twbTest that the image works:
docker run --rm -v $PWD:$PWD -w $PWD twb \
twb cli input.csv -o output.csv -r $refTip! It may be convenient to write a wrapper for the Docker call and tus avoid writing a long command every time. That can be done by executing the commands:
cat > twb-cli << EOF
#!/bin/bash
docker run --rm -v \$PWD:\$PWD -w \$PWD aryashta/twb:latest twb cli \$*
EOF
chmod +x twb-cliThe resulting wrapper file twb-cli can now be moved to somewhere on the execution path (e.g. to /usr/local/bin/) and then called directly:
twb-cli -r $ref -o output.csv input.csv Note that the file system mapping used in the wrapper only exposes the current working directory and its subdirectories for the TWB container. If you get “File not found” error, check that the files are real files and not links to somewhere else in the file system.
Local / pip install
# if using virtual environment, activate it first
source twb_env/bin/activate
twb cli --helpAvailable command-line parameters
The current dedup_cli.py includes the following short options:
-h --help
-o --output
-r --reference / --ref
-g --gff
-m --mask
-O --filter-only
-d --dedup-only
--duplicate-mode {group,collapse,off}
-n --no-dedup (deprecated alias for --duplicate-mode off)
-k --key
-K --keep
-R --report-json
--report-only
-I --keep-intermediate
-p --filter-preset-json
-P --filter-preset
-J --filter-json
-f --filter
-A --filter-mode
-x --missing-filter-column
-L --list-columns
-q --query
--query-json
Note: the current CLI has short aliases for common arguments, but it does not currently define convenience shortcut filters such as --likely-tsm or --min-final-score. Use -f/--filter for column-specific filtering.
CLI: inspect available columns
Use -L / --list-columns to print the CSV header and exit. This mode does not require -o:
twb cli output.processed.csv -LThis is useful before writing filters, because processed CSVs can contain many annotation columns.
CLI: full post-processing mode
Use full post-processing when you want the enriched CSV that the browser produces after upload.
twb cli input.csv \
-o output.processed.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
-g ref/annotations/hg38/Homo_sapiens.GRCh38.115.ucsc.sorted.gff3.gz \
-m ref/masks/hg38/hg38.no_alt.masking.v2.sorted.gff3.gz \
-R postprocess_report.jsonRequired for full post-processing:
-r, --reference, --ref
Optional:
-g, --gff
-m, --mask
-R, --report-json
-I, --keep-intermediate
If --gff is omitted, gene-context annotation is skipped. If --mask is omitted, repeat-mask annotation is skipped.
Repeated-event handling in full preprocessing
Use --duplicate-mode to control how observations with the same repeated-event signature are handled. The grouping signature uses the same cluster_region, normalized inner CIGAR, and 10 bp of expanded CIGAR context on both sides of the template-switch block.
Group and retain all observations, default
twb cli input.csv \
-o output.grouped.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
--duplicate-mode groupgroup preserves every observation, adds repeated-event metadata, and marks one representative observation per group. This mode is recommended for trios, families, and multi-sample datasets.
Collapse repeated groups
twb cli input.csv \
-o output.collapsed.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
--duplicate-mode collapsecollapse keeps one representative observation per repeated-event group. This is the legacy-style behavior for users who want one output row per grouped event.
Disable repeated-event grouping
twb cli input.csv \
-o output.ungrouped.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
--duplicate-mode offoff preserves and processes every row independently. -n/--no-dedup remains available as a deprecated alias for --duplicate-mode off.
The legacy -d/--dedup-only command is different: it performs lightweight exact-column deduplication and does not run the full annotation pipeline or the new CIGAR-context grouping logic.
Full post-processing followed by filtering
The current CLI can apply filters after full preprocessing by adding filter arguments to the full preprocessing command. The processed output is copied to the requested output path and then filtered in place:
twb cli input.csv \
-o output.processed.likely.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
-g ref/annotations/hg38/Homo_sapiens.GRCh38.115.ucsc.sorted.gff3.gz \
-m ref/masks/hg38/hg38.no_alt.masking.v2.sorted.gff3.gz \
-f tsm_confidence_label:eq:"Likely TSM" \
-f tsm_final_score:gte:6 \
-R output.processed.likely.report.jsonFor reproducibility, a two-step workflow is often clearer:
# 1. Produce an enriched processed CSV
twb cli input.csv \
-o output.processed.csv \
-r ref/genomes/hg38/hg38.no_alt.fa.gz \
-g ref/annotations/hg38/Homo_sapiens.GRCh38.115.ucsc.sorted.gff3.gz \
-m ref/masks/hg38/hg38.no_alt.masking.v2.sorted.gff3.gz
# 2. Apply filters to the processed CSV
twb cli output.processed.csv \
-O \
-f tsm_confidence_label:eq:"Likely TSM" \
-o output.processed.filtered.csv \
-R output.processed.filtered.report.jsonCLI: label sample_name values
Twitcher output uses sample_name as the per-row sample identifier. The sample name inferred from the input data may not be ideal for the downstream analyses, and twb cli allows modifying it.
Non-interactive inline labeling
twb cli output.processed.csv \
-O \
--sample-label 'NA12878=Mother' \
--sample-label 'NA12891=Father' \
--sample-label 'NA12892=Child' \
-o output.labeled.csvNon-interactive JSON labeling
twb cli output.processed.csv \
-O \
--sample-label-json trio-labels.json \
-o output.labeled.csvThe JSON file maps exact sample_name values to display labels:
{
"NA12878": "Mother",
"NA12891": "Father",
"NA12892": "Child"
}Interactive labeling
twb cli output.processed.csv \
-O \
--sample-label-interactive \
--sample-label-output-json trio-labels.json \
-o output.labeled.csvHandling unmapped sample_name values
sample_label is always populated: full post-processing (process_csv_job, used by both the web viewer and this CLI’s full preprocessing mode) automatically defaults sample_label to the raw sample_name for any row without an explicit label. --unmapped-sample-label controls what --sample-label/--sample-label-json/--sample-label-interactive do with identifiers not present in the supplied mapping, on top of that baseline:
sample-name Copy the original sample_name into sample_label. This is the default.
empty Leave sample_label blank (opt back into the old behavior).
error Stop if any non-empty sample_name has no label.
Mapping precedence for sample labels
- Existing non-empty
sample_labelvalues in the input CSV. - Values loaded from
--sample-label-json. - Repeated
--sample-labelarguments. - Changes made by
--sample-label-interactive.
Later sources override earlier sources for the same exact sample_name.
Renaming a sample label permanently (web UI)
The web UI’s rename button (pencil icon on a sample badge) calls POST /rename_identity_label, which rewrites sample_label for every matching row directly in the processed CSV on disk, atomically. The rename therefore survives a reload and is reflected in exports — it is not just a browser-local override. The raw sample_name column is never modified by a rename, and no repeated-event regrouping is needed or triggered: duplicate_group_id never depends on the identity or label columns (see ADR 0001, ADR 0002).
Filter observations by sample_label
After labels are assigned, sample_label can be used like any other column:
twb cli output.processed.csv \
-O \
--sample-label-json trio-labels.json \
-f 'sample_label:eq:Child' \
-o child-events.csvCLI: repeated-event group filters
Observation filters inspect one row at a time. Group filters inspect all observations belonging to the same duplicate_group_id. Group filtering is intended for trio, family, and multi-sample questions such as:
- present in Child, Mother, and Father;
- present in Child and Mother but absent from Father;
- present in any parent;
- present in exactly a selected set of labeled samples.
Group presence and absence are evaluated before observation-level filtering, using the complete retained group. This prevents a normal row filter from making an existing Father observation appear absent.
Group filtering requires output created with:
--duplicate-mode group
Do not use pedigree group filters on collapse-mode output because non-representative observations have already been removed.
Group filter operators
Supported group-filter operators are:
group_has_all Every selected value must occur somewhere in the group.
group_has_any At least one selected value must occur somewhere in the group.
group_has_none None of the selected values may occur in the group.
group_exact The observed value set must exactly equal the selected set.
The syntax is:
--group-filter 'COLUMN:OPERATOR:VALUE1,VALUE2'
Present in Child, Mother, and Father
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter 'read_label:group_has_all:Child,Mother,Father' \
-o complete-trio-events.csvPresent in Child and Mother, but absent from Father
Separate group filters are combined with AND by default:
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter 'read_label:group_has_all:Child,Mother' \
--group-filter 'read_label:group_has_none:Father' \
--group-filter-mode all \
-o child-mother-not-father.csvPresent in either parent
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter 'read_label:group_has_any:Mother,Father' \
-o present-in-parent.csvExact labeled composition
This matches groups containing Child and Mother, but excludes groups that also contain Father or another label:
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter 'read_label:group_exact:Child,Mother' \
-o exact-child-mother.csvCombine group and observation filters
The following first selects groups present in the complete trio, then retains only Child observations classified as Likely TSM:
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter 'read_label:group_has_all:Child,Mother,Father' \
-A all \
-f 'read_label:eq:Child' \
-f 'tsm_confidence_label:eq:Likely TSM' \
-o trio-child-likely-tsm.csvCombine separate group filters with AND or OR
Use:
--group-filter-mode all
to require every separate group filter, logical AND. This is the default.
Use:
--group-filter-mode any
to accept a group when at least one separate group filter matches, logical OR.
Group filters from JSON
Use --group-filter-json with a raw JSON list:
[
{
"col": "read_label",
"op": "group_has_all",
"val": ["Child", "Mother"]
},
{
"col": "read_label",
"op": "group_has_none",
"val": ["Father"]
}
]Run:
twb cli output.processed.csv \
-O \
--read-label-json trio-labels.json \
--group-filter-json pedigree-filters.json \
--group-filter-mode all \
-o child-mother-not-father.csvCLI: filter-only mode
Use -O / --filter-only when you already have a processed CSV and only want to apply filters.
Filter-only mode does not run:
- preprocessing
- deduplication
- complexity annotation
- TSM scoring
- gene annotation
- repeat-mask annotation
Filter-only mode requires at least one filter source:
-f / --filter
-J / --filter-json
-p / --filter-preset-json
Inline filters with -f/--filter
The most direct syntax is:
-f COL:OP:VALUE
The option can be repeated.
twb cli output.processed.csv \
-O \
-f tsm_confidence_label:eq:"Likely TSM" \
-o likely_tsm.csvMultiple filters are combined with AND by default:
twb cli output.processed.csv \
-O \
-f tsm_confidence_label:eq:"Likely TSM" \
-f tsm_final_score:gte:6 \
-f tsm_evidence_score:gte:8 \
-o high_confidence_tsm.csvUse -A any / --filter-mode any to combine filters with OR:
twb cli output.processed.csv \
-O \
-A any \
-f is_microsatellite:eq:1 \
-f gene_context:eq:exonic \
-o microsatellite_or_exonic.csvFor empty and notempty, the value can be omitted:
twb cli output.processed.csv \
-O \
-f gene_names:notempty \
-o gene_overlapping_events.csvCommon inline filter examples
Likely TSM events:
twb cli output.processed.csv -O \
-f tsm_confidence_label:eq:"Likely TSM" \
-o likely_tsm.csvRepeat-associated TSM-like events:
twb cli output.processed.csv -O \
-f tsm_confidence_label:eq:"Repeat-associated TSM-like" \
-o repeat_associated_tsm_like.csvHigh final score:
twb cli output.processed.csv -O \
-f tsm_final_score:gte:6 \
-o min_final_score_6.csvMicrosatellite-associated events:
twb cli output.processed.csv -O \
-f is_microsatellite:eq:1 \
-o microsatellite_events.csvInsertion-containing events, using the quantitative inserted-length column:
twb cli output.processed.csv -O \
-f tsm_inserted_len:gt:0 \
-o insertion_events.csvEvents with indel footprint:
twb cli output.processed.csv -O \
-f tsm_indel_len:gt:0 \
-o indel_events.csvPalindrome-capable events:
twb cli output.processed.csv -O \
-f tsm_palindrome_capable:eq:1 \
-o palindrome_capable_events.csvEvents overlapping at least one of several pipe-separated gene names, OR within one filter:
twb cli output.processed.csv -O \
-f gene_names:has_any:LINC00681,LINC03019 \
-o selected_gene_events.csvEvents whose same gene_names cell contains all selected names, AND within one filter:
twb cli output.processed.csv -O \
-f gene_names:has_all:BRCA1,TP53 \
-o brca1_and_tp53_events.csvFor has_all, all requested values must occur in the same observation row. Values split across different observations do not satisfy the filter.
Events with selected repeat text in repeat_types_raw:
twb cli output.processed.csv -O \
-f repeat_types_raw:contains:LINE \
-o line_repeat_events.csvFour-point model examples:
# Inverted repeat class
twb cli output.processed.csv -O \
-f tsm_four_point_class:contains:"Inverted repeat" \
-o inverted_repeat_events.csv
# Observed four-point groups only
twb cli output.processed.csv -O \
-f tsm_four_point_observed:eq:1 \
-o observed_four_point_events.csv
# Group B novel four-point events
twb cli output.processed.csv -O \
-f tsm_four_point_group:eq:B \
-o group_b_four_point_events.csvSupported filter operators
Filter objects use the same frontend-style shape used by the web viewer:
{"col": "column_name", "op": "eq", "val": "value"}Supported operators:
eq
neq
contains
not_contains
starts_with
ends_with
gt
lt
gte
lte
between
empty
notempty
in
notin
has_any
has_all
has_none
region_overlaps
region_within
region_contains
region_distance_lt
cigar_has_insertion
cigar_has_deletion
cigar_has_mismatch
cigar_insertion_count_gt
cigar_deletion_count_gt
cigar_mismatch_count_gt
Operator notes:
containsandnot_containsperform case-insensitive substring matching (present/absent).starts_withandends_withperform case-insensitive prefix/suffix matching.eqandneqare numeric-aware, so a filter value of1can match CSV values such as1and1.0.gt,lt,gte, andlteconvert the column to numeric values.betweenis an inclusive numeric range check: through-f, writeLOW,HIGH, e.g.5,10. Through--query/--query-json, use a two-element list:[5, 10].inandnotinaccept comma-separated values when used through-f.has_any,has_all, andhas_noneare intended for pipe-separated fields such asgene_namesorgene_feature_types; through-f, provide comma-separated wanted values.has_any:A,Bmatches a cell containing at least one selected value, equivalent toA OR Bwithin that filter.has_all:A,Bmatches only when the same cell contains every selected value, equivalent toA AND Bwithin that filter.has_none:A,Bmatches when the cell contains none of the selected values.region_overlaps,region_within, andregion_containsoperate on genomic-region columns such ascluster_regionorts_1_4_region(formatchrom:start-end); a row’s region must be on the same chromosome as the filter value to match.region_distance_ltalso operates on genomic-region columns, but takes a compound value: through-f, writeREGION,DISTANCE(region, then a comma, then the maximum distance in bp), e.g.chr1:1000-2000,500. Through--query/--query-json, use{"region": "chr1:1000-2000", "distance": 500}instead.cigar_has_insertion,cigar_has_deletion, andcigar_has_mismatchoperate on CIGAR columns such asts_cigar_ctxand take no value, likeempty/notempty:col:cigar_has_insertion. They match when the CIGAR string contains at least oneI,D, orXoperation respectively.cigar_insertion_count_gt,cigar_deletion_count_gt, andcigar_mismatch_count_gtalso operate on CIGAR columns, and take a single numeric threshold, e.g.col:cigar_insertion_count_gt:2. They match when the total summed length of that CIGAR operation exceeds the threshold.
Region operator examples
Events whose ts_1_4_region overlaps a region of interest:
twb cli output.processed.csv -O \
-f ts_1_4_region:region_overlaps:chr1:100000-200000 \
-o overlapping_events.csvEvents entirely within a region:
twb cli output.processed.csv -O \
-f ts_1_4_region:region_within:chr1:100000-200000 \
-o within_region_events.csvEvents whose region fully contains a smaller region of interest:
twb cli output.processed.csv -O \
-f ts_1_4_region:region_contains:chr1:150000-150100 \
-o containing_events.csvEvents within 500 bp of a region of interest:
twb cli output.processed.csv -O \
-f ts_1_4_region:region_distance_lt:chr1:150000-150100,500 \
-o nearby_events.csvEvents excluding an exact region (neq) and excluding a chromosome (not_contains):
twb cli output.processed.csv -O \
-f ts_1_4_region:neq:chr1:100000-200000 \
-f ts_1_4_region:not_contains:chrY \
-o filtered_events.csvNumeric-range and CIGAR operator examples
Events with a final score in an inclusive range (between):
twb cli output.processed.csv -O \
-f tsm_final_score:between:5,10 \
-o mid_confidence_events.csvEvents whose alignment CIGAR contains at least one insertion:
twb cli output.processed.csv -O \
-f ts_cigar_ctx:cigar_has_insertion \
-o insertion_cigar_events.csvEvents with more than 2 bp of deletion in the CIGAR:
twb cli output.processed.csv -O \
-f ts_cigar_ctx:cigar_deletion_count_gt:2 \
-o large_deletion_events.csvEvents with an insertion in the CIGAR, combined with a score range:
twb cli output.processed.csv -O \
-A all \
-f ts_cigar_ctx:cigar_has_insertion \
-f tsm_final_score:between:5,10 \
-o insertion_mid_confidence_events.csv-f’s flat COL:OP:VALUE syntax has no negation, so there is no built-in “does not have a mismatch” form for cigar_has_mismatch. To exclude mismatch-containing events instead, use --query/--query-json with a negated group around cigar_has_mismatch (see “CLI: advanced query filtering” below).
Filter combination mode: AND versus OR
-A/--filter-mode controls how separate filter expressions are combined.
Default mode is all, meaning every separate filter must match, logical AND:
twb cli output.processed.csv -O \
-A all \
-f tsm_final_score:gte:6 \
-f tsm_inserted_len:gt:0 \
-o high_score_insertions.csvUse any when at least one separate filter may match, logical OR:
twb cli output.processed.csv -O \
-A any \
-f is_microsatellite:eq:1 \
-f repeat_overlap:eq:1 \
-o microsatellite_or_repeat_overlap.csvThis is separate from multi-value behavior inside one filter:
in:A,Bandhas_any:A,Buse OR among their values.has_all:A,Buses AND among its values and requires both values in the same cell.--filter-mode allor--filter-mode anycombines separate-ffilters.
For example, the following requires one observation to contain both BRCA1 and TP53, and also requires an exonic gene context:
twb cli output.processed.csv -O \
-A all \
-f gene_names:has_all:BRCA1,TP53 \
-f gene_context:eq:exonic \
-o exonic_brca1_tp53_events.csvMissing filter columns
By default, missing filter columns are skipped and recorded in the report:
twb cli output.processed.csv -O \
-f missing_column:eq:1 \
-o filtered.csv \
-R filtered.report.jsonUse -x error / --missing-filter-column error to fail instead:
twb cli output.processed.csv -O \
-x error \
-f missing_column:eq:1 \
-o filtered.csvFilter-only with exported web preset JSON
The web UI can export filter presets to JSON. Use -p / --filter-preset-json to load an exported preset file, and -P / --filter-preset to choose the preset by name or id:
twb cli output.processed.csv \
-O \
-p twitcher-filter-presets.json \
-P "Perfect 30bp identity" \
-o output.processed.filtered.csv \
-R output.processed.filtered.report.jsonIf the preset JSON contains exactly one preset, -P/--filter-preset can be omitted:
twb cli output.processed.csv \
-O \
-p one-preset.json \
-o output.processed.filtered.csvIf the preset JSON contains multiple presets, -P/--filter-preset is required.
Filter-only with raw filter JSON
Use -J / --filter-json to provide a raw list of filters without the preset wrapper.
Example filters.json:
[
{
"col": "identity_30bp_upstream",
"op": "eq",
"val": "1"
},
{
"col": "identity_30bp_downstream",
"op": "eq",
"val": "1"
}
]Run:
twb cli output.processed.csv \
-O \
-J filters.json \
-o output.processed.filtered.csv \
-R output.processed.filtered.report.jsonCombining preset/JSON filters with inline filters
The CLI appends inline -f filters to filters loaded from -p/--filter-preset-json or -J/--filter-json:
twb cli output.processed.csv \
-O \
-p twitcher-filter-presets.json \
-P "Perfect 30bp identity" \
-f tsm_final_score:gte:6 \
-o perfect_identity_score6.csvCLI: advanced query filtering
Use --query or --query-json when flat -f filters are not expressive enough. The query engine accepts a JSON AST with nested AND/OR groups and negation, using the same structure as the web viewer’s advanced filter.
This is useful for conditions such as:
- (score ≥ 6 AND label = Likely TSM) OR gene_context = exonic
- NOT (is_microsatellite = 1 AND repeat_overlap = 1)
Query AST format
{
"type": "group",
"combinator": "and",
"negated": false,
"children": [
{
"type": "rule",
"column": "tsm_confidence_label",
"operator": "eq",
"value": "Likely TSM"
},
{
"type": "rule",
"column": "tsm_final_score",
"operator": "gte",
"value": "6"
}
]
}Supported combinators: and, or. Set "negated": true on any group to invert it. Supported operators inside rules: eq, neq, contains, not_contains, starts_with, ends_with, gt, lt, gte, lte, empty, notempty, in, notin, has_any, has_all, has_none, region_overlaps, region_within, region_contains, region_distance_lt.
The region operators apply to genomic-region columns such as cluster_region or ts_1_4_region (format chrom:start-end). region_distance_lt takes a compound value, {"region": "chrom:start-end", "distance": <bp>}:
{
"type": "rule",
"column": "ts_1_4_region",
"operator": "region_distance_lt",
"value": {"region": "chr1:150000-150100", "distance": 500}
}Inline query from the CLI
Pass a JSON string directly with --query:
twb cli output.processed.csv \
-O \
--query '{"type":"group","combinator":"and","negated":false,"children":[{"type":"rule","column":"tsm_confidence_label","operator":"eq","value":"Likely TSM"},{"type":"rule","column":"tsm_final_score","operator":"gte","value":"6"}]}' \
-o likely_tsm_score6.csvQuery from a file
Save the AST to a JSON file and use --query-json:
twb cli output.processed.csv \
-O \
--query-json my_query.json \
-o filtered.csv \
-R filtered.report.jsonNested OR group example
Keep rows where either the label is Likely TSM, or the gene context is exonic:
{
"type": "group",
"combinator": "or",
"negated": false,
"children": [
{
"type": "rule",
"column": "tsm_confidence_label",
"operator": "eq",
"value": "Likely TSM"
},
{
"type": "rule",
"column": "gene_context",
"operator": "eq",
"value": "exonic"
}
]
}Combining query filtering with observation filters
Query filters are applied first, then observation -f filters. Use --query-json for the nested part and -f for flat additions:
twb cli output.processed.csv \
-O \
--query-json nested_query.json \
-f gene_names:notempty \
-o filtered_with_genes.csvNote: --query and --query-json are mutually exclusive. Use one or the other.
CLI: filter reports
When -R/--report-json is provided, reports include a filtering section:
{
"mode": "filter_only",
"input_csv": "output.processed.csv",
"output_csv": "output.processed.filtered.csv",
"filtering": {
"preset_id": "preset_1780492344850_ybn021t5lg",
"preset_name": "Perfect 30bp identity",
"num_filters": 2,
"filter_mode": "all",
"missing_filter_column_policy": "skip",
"filters_applied": 2,
"rows_before_filter": 24454,
"rows_after_filter": 4321,
"rows_removed_by_filter": 20133,
"missing_filter_columns": [],
"filter_steps": [
{
"filter": {
"col": "identity_30bp_upstream",
"op": "eq",
"val": "1"
},
"status": "applied",
"rows_before_this_filter": 24454,
"rows_matching_this_filter_alone": 18000,
"rows_after_this_filter": 18000
}
]
}
}filter_steps is useful for debugging filters or presets that unexpectedly remove too many rows.
CLI: dedup-only mode
Use -d / --dedup-only when you only want the old lightweight deduplication behavior.
twb cli input.csv \
-o output.dedup.csv \
-d \
-R dedup_report.jsonBy default, dedup-only mode uses:
cluster_region + ts_cigar_ctx
If ts_cigar_ctx is missing, the CLI falls back to ts_cigar.
Override the deduplication key:
twb cli input.csv \
-o output.dedup.csv \
-d \
-k cluster_region,ts_cigar_ctx \
-K firstAvailable -K/--keep values:
first
last
Dedup-only output can also be filtered in the same command:
twb cli input.csv \
-o output.dedup.filtered.csv \
-d \
-f is_microsatellite:eq:1CLI: report-only mode
Report-only mode applies to deduplication reports:
twb cli input.csv \
-o unused.csv \
-d \
--report-only \
-R dedup_report.jsonCLI: efficiency tips
List columns before writing filters. On any CSV you haven’t seen before, run -L first. It prints the header and exits without requiring -o:
twb cli output.processed.csv -LPreprocess once, filter many times. Full preprocessing (FASTA alignment, TSM scoring, gene annotation) is slow. Once you have an enriched CSV, each -O filter-only run is fast. The two-step pattern is always clearer and more reproducible than combining preprocessing and filtering in one command.
Always pass -R report.json. The filter_steps array in the report shows the row count before and after each individual filter. When a filter removes more rows than expected, filter_steps tells you exactly which one is responsible.
Save interactive labels for reuse. After --read-label-interactive, add --read-label-output-json trio-labels.json. The saved JSON can be replayed with --read-label-json in any future run without re-entering labels manually.
Extend presets with inline -f filters. Inline -f arguments are appended to filters loaded from -p / --filter-preset-json. You can tighten an exported web preset with one or two extra CLI filters without editing the JSON file:
twb cli output.processed.csv \
-O \
-p my-preset.json \
-P "Perfect 30bp identity" \
-f tsm_final_score:gte:6 \
-o strict_filtered.csvKeep --duplicate-mode group if you plan to use pedigree filters later. The collapse mode removes non-representative observations, which breaks --group-filter logic. Process with group (the default), then use -O --group-filter in a separate filter-only step.
Use --query/--query-json for nested logic. Flat -f filters can only combine with a single AND or OR. For nested conditions such as (A AND B) OR C, use the query AST. See the advanced query filtering section above.
Avoid -x error / --missing-filter-column error in exploratory runs. The default skip behaviour mirrors the web viewer and lets you reuse preset JSON files on CSVs that may be missing optional columns. Switch to error only in production pipelines where a missing column should be a hard failure.