# Using jexl callbacks

**TL;DR:** a config callback is a string prefixed with `jexl:`. Read feature
attributes as plain properties (`feature.strand`). When an expression outgrows
one line, register your own function from a small plugin and call it like a
built-in.

A callback is a [Jexl](https://github.com/TomFrost/Jexl) expression in a slot
that takes one, `"color": "jexl:feature.strand==-1?'red':'blue'"`. Any feature
attribute is a plain property, nested attributes work (`feature.INFO.SVTYPE`),
and `feature.parent` is the parent feature:

```js
jexl: feature.start // start coordinate, 0-based half open
jexl: feature.end // end coordinate, 0-based half open
jexl: feature.refName // chromosome or reference sequence name
jexl: feature.CIGAR // BAM or CRAM feature CIGAR string
jexl: feature.seq // BAM or CRAM feature sequence
jexl: feature.type // feature type e.g. mRNA or gene
jexl: feature.id // the feature's id attribute, e.g. a GFF3 ID=
jexl: feature.parent // parent feature, e.g. the gene of an mRNA (undefined if none)
```

The [cookbook](https://jbrowse.org/jb2/docs/cookbook#colors) has the common expressions (a lookup table
by type, a threshold, a gradient, a label with a fallback), and the
["Jexl callback examples" track](https://jbrowse.org/code/jb2/main/?config=test_data/config_demo.json&assembly=hg19&tracks=jexl_callbacks_demo_hg19)
on the hosted demo combines a lookup-table color with a template-string
mouseover. `formatDetails` is the one slot family whose callback returns an
object, one key per row
([customizing feature details](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_details)).

### Property access vs `get()` {#property-access-vs-get}

`feature.start` and `get(feature,'start')` are equivalent; `get()` also works on
older JBrowse releases. What `feature` is depends on the callback:

| Callback                                                                 | `feature` is                    | Property form | `get()` form |
| ------------------------------------------------------------------------ | ------------------------------- | ------------- | ------------ |
| Color, label, tooltip, filter (`color`, `name`, `mouseover`, `filterBy`) | a `SimpleFeature`               | yes           | yes          |
| [`formatDetails`](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_details)       | a plain object from the session | yes           | **no**       |

In JavaScript plugin code a `SimpleFeature` handed to your own function is the
real object, read with `feature.get('start')`.

## Functions

Beyond the feature's own properties, jexl has these functions. `getTag` smooths
over the differences between BAM and CRAM features to reach their tags.

<!-- JEXL_CATALOG START -->

**Math functions**

```js
jexl: max(0, 2)
jexl: min(0, 2)
jexl: sqrt(4)
jexl: ceil(0.5)
jexl: floor(0.5)
jexl: round(0.5)
jexl: abs(-0.5)
jexl: log10(50000)
jexl: parseInt('2')
jexl: parseFloat('2.054')
```

**String functions**

```js
jexl: charAt('abc', 2) // c
jexl: charCodeAt(' ', 0) // 32
jexl: codePointAt(' ', 0) // 32
jexl: startsWith('kittycat', 'kit') // true
jexl: endsWith('kittycat', 'cat') // true
jexl: padStart('cat', 8, 'kitty') // kittycat
jexl: padEnd('kitty', 8, 'cat') // kittycat
jexl: replace('kittycat', 'cat', '') // kitty
jexl: replaceAll('kittycatcat', 'cat', '') // kitty
jexl: slice('kittycat', 5) // cat
jexl: substring('kittycat', 0, 5) // kitty
jexl: trim('  kitty ') // kitty, whitespace trimmed
jexl: trimStart('  kitty ') // kitty, starting whitespace trimmed
jexl: trimEnd('  kitty ') // kitty, ending whitespace trimmed
jexl: toUpperCase('kitty') // KITTY
jexl: toLowerCase('KITTY') // kitty
jexl: split('KITTY KITTY', ' ') // ['KITTY', 'KITTY']
jexl: split(feature.notThere, ' ') // [''], an absent value is read as the empty string rather than throwing
jexl: join('-', 'a', 'b', '', 'c') // a-b-c, joins truthy args with the separator
jexl: includes('kittycat', 'cat') // true
jexl: repeat('ab', 3) // ababab
jexl: jsonParse('{"a":1}') // parses a JSON string
```

**Feature operations - getTag**

```js
jexl: getTag(feature, 'MD') // fetches MD string from BAM or CRAM feature
jexl: getTag(feature, 'HP') // fetches haplotype tag from BAM or CRAM feature
```

**Color functions**

```js
jexl: randomColor(feature.type) // deterministic color from a string (e.g. a feature type)
jexl: alpha('green', 0.5) // a color at 50% opacity
jexl: hsl('#ff0000') // converts a color to its HSL form
jexl: colorString('green') // normalizes a color name or value to a hex string
```

**Console logging**

```js
jexl: log(feature) // console.logs output and returns value
```

**Binary operators**

```js
jexl: feature.flags & 2 // bitwise and to check if BAM or CRAM feature flags has 2 set
```

**Slot defaults from plugins**

```js
jexl: logThickness(feature, 'score') // log(attribute + 1) where that is a width, else 1px; the arc display's default thickness
jexl: defaultPairedArcColor(feature, alt) // a color per SV type read off the ALT (DEL, DUP, INV, TRA, CNV)
jexl: lgvSyntenyTooltip(feature) // both sides of a synteny feature, the LGVSyntenyDisplay's default mouseover
jexl: defaultOnChordClick(feature, track, pluginManager) // opens a breakpoint split view on the clicked chord
jexl: svChordColor(feature) // the SV-type color the inspector's chords are drawn in
```

**Variant functions**

```js
jexl: maf(feature) // minor allele frequency over the called alleles
jexl: missingness(feature) // fraction of samples with no call
jexl: impact(feature) // HIGH, MODERATE, LOW or MODIFIER, from SnpEff ANN / VEP CSQ
jexl: consequence(feature) // e.g. missense_variant, from the same annotation — the MOST SEVERE one alone
jexl: 'missense_variant' in consequences(feature) // every consequence term on the record, across all transcripts (bcftools INFO/CSQ ~ "missense_variant")
jexl: impactColor(feature) // the color the "Color by consequence impact" menu item uses
jexl: svTypeColor(feature) // the color "Color by SV type" uses
jexl: alleleLength(feature) >= 50 // longest allele in bp, so an insertion is not measured by its reference span
jexl: svType(feature) == 'DEL' // SV class, read off a symbolic ALT before falling back to INFO/SVTYPE (bcftools INFO/SVTYPE)
jexl: nAlt(feature) == 1 // ALT alleles the record declares, i.e. biallelic-only (bcftools N_ALT)
jexl: genotypeCount(feature, 'het') > 0 // samples in a genotype class — ref, alt, hom, het or mis (bcftools N_PASS(GT="het"))
```

<!-- JEXL_CATALOG END -->

The catalog is generated from the registrations themselves, core's in
[`packages/core/src/util/jexl.ts`](https://github.com/GMOD/jbrowse-components/blob/main/packages/core/src/util/jexl.ts)
and each plugin's beside the display it serves. The last two groups come from
plugins that ship with JBrowse:

- **the variant functions** are what the variant track's filter and color menus
  write, so a menu choice can be copied into a config and edited
  ([variant tracks](https://jbrowse.org/jb2/docs/config_guides/variant_track))
- **the slot defaults** are what those slots evaluate to unconfigured, listed so
  you can compose with one

**Template strings.** The jexl fork supports backtick template literals with
`${...}` interpolation, so a color derived from a value is
``"color": "jexl:`hsl(${feature.start/100000},50%,50%)`"``.

## Adding your own jexl function

Jexl has no variables or branchy helpers, so past a certain point an expression
stops being readable. A small plugin file with no build step adds a function to
the language, called like any built-in: `"color": "jexl:customColor(feature)"`.
The [no-build plugin tutorial](https://jbrowse.org/jb2/docs/developer_guides/no_build_plugin) is the
plugin;
[customizing feature colors](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_colors) and
[customizing feature details](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_details)
call it from a color slot and a details slot.

## See also

- [](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_colors)
- [](https://jbrowse.org/jb2/docs/config_guides/customizing_feature_details)
- [](https://jbrowse.org/jb2/docs/user_guides/variant_track)
- [](https://jbrowse.org/jb2/docs/user_guides/alignments_track)

