Skip to content

Element mapping

cau element-mapping says which element of a screen each guide tests. It is the third step: alignment finds where a guide is, annotation says what gene it falls in, and this maps it to the regions the experiment targets.

In Claude Code the cau-element-mapping skill teaches Claude to run it and read the output (Agents and skills).

Quick start

cau element-mapping run \
    --alignment results/alignments/guide_genome_annotation.tsv \
    --annotation results/annotations/guide_gene_annotation.tsv \
    --elements elements.bed \
    --outdir results/

--genes is optional and fills putative_target_genes from the same pairs table cau igvf-export takes, so the two tables name the same genes. --annotation is optional and fills distance_to_tss; the classes do not depend on it. Nothing is written outside --outdir.

The three classes

Decided per site, not per guide, so a guide whose sites disagree reports each of them.

Class Means
targeting The protospacer overlaps this element
safe_targeting The guide maps, but the site overlaps no element
non_targeting The guide matches nowhere in the genome

There is deliberately no fourth class and no distance threshold. An earlier draft called a guide safe only beyond 1 Mb from any protein-coding TSS, which put most of a real library's safe-targeting controls somewhere else: that design had measured safety against the screen's own readout genes, not every promoter. Both definitions are defensible, which is the point — the tool reports distance_to_tss and lets the analysis choose.

Outputs

--outdir gets three folders and nothing loose:

elements/        guide_element_mapping.tsv  qc.tsv
                 guide_element_mapping_columns.yaml
run_metadata/    element_mapping_<UTC timestamp>.json
logs/            element_mapping.log

guide_element_mapping.tsv

One row per site per element it overlaps. A site inside two overlapping elements gets two rows. A guide that matches nowhere gets one row with no site and no element.

Column Holds
guide_id The aligned sequence. With the four site columns, the key back to guide_genome_annotation.tsv.
chr, start, end, strand The protospacer, 0-based and half-open. Empty when the guide matches nowhere.
element_id The element this site overlaps. Empty unless targeting.
element_category The elements BED's fifth column, when it has one.
target_class targeting, safe_targeting or non_targeting.
distance_to_tss Signed bases from the target site to the nearest protein-coding TSS, carried from the annotation.
putative_target_genes Semicolon-separated ENSEMBL ids measured against the element, from --genes. The same genes the IGVF export carries.

The classes are per site

A guide with two sites whose classes differ reports both rows, because the two sites really do different things:

guide_id   chr    start     element_id               target_class
G...NGG    chr10  86958386  chr10:86958280-86958780  targeting
G...NGG    chr17  79714569                           safe_targeting

safe_targeting is not a promise

It says only that the site maps and overlaps none of the elements given. How far from a gene a guide has to be before it is safe depends on what the screen reads out, so that is left to distance_to_tss rather than fixed by a threshold here. Threshold it yourself, and say which threshold you used.

It follows that an incomplete element list inflates safe_targeting: every guide for a missing element lands there. Check the count against the library design before believing it.

qc.tsv

Three columns, section, name, value: how the library covers the elements, which is the question the mapping table cannot answer by itself.

Section Says
classes How many guides, and how many sites in each class
elements Total, how many have a guide, how many have none, and how many are below half the median density
guides_per_element Median, min, max, and the median per 100 bases
category The same per element category, so a thinly covered kind of element stands out
untiled_elements How far the elements with no guide are from the nearest mapped one

Two of these earn their place:

  • Density, not count. A wide element collects more guides without being better covered, so median_per_100bp and below_half_median_density are what find the elements that are actually thin.
  • Distance for the untiled ones. An element a few hundred bases from the nearest guide was missed at its boundary; one tens of kilobases away was never targeted at all. Only the second is a hole in the design.

element_id

Taken from the BED's fourth column when it has one, so an id used elsewhere keeps its spelling. Otherwise built as chr:start-end with a 1-based start, which is how a locus is read aloud and how most element tables write it.

Use it to check the design

A library's own labels are a hypothesis. Mapping a real 43,778-guide library against its element list disagreed with the shipped annotation in two ways, in opposite directions:

  • 18 guides labelled non-targeting cut inside a targeted element. All 18 are exact 20-nt protospacers with a real NGG, read straight back out of the reference. The aligner the old pipeline used had missed them, so genuine cutters were used as controls.
  • 45 guides assigned to an element do not reach it. That pipeline stripped a 5' G before aligning and so searched a 19-mer, which matches places the real 20-mer does not.

Both contaminate a downstream test, in opposite directions, and neither is visible without redoing the mapping from the sequences.