Customizing feature details
The track slot formatDetails takes jexl callbacks that return an object of
fields to merge onto a feature: a new key adds a row, an existing key overrides
it, and undefined/null hides it. formatAbout does the same for the About
track dialog. For complex logic, register a jexl function in a small plugin.
Goes in the tracks array of config.json. See Tracks.
{
"trackId": "genes",
"assemblyNames": ["volvox"],
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"formatDetails": {
"feature": "jexl:{name:'<a href=https://google.com/?q='+feature.name+'>'+feature.name+'</a>',extrafield:'Field added with custom callback:' + feature.name,phase:undefined,type:undefined}"
}
}jbrowse add-track-json '{
"trackId": "genes",
"assemblyNames": ["volvox"],
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"formatDetails": {
"feature": "jexl:{name:'\''<a href=https://google.com/?q='\''+feature.name+'\''>'\''+feature.name+'\''</a>'\'',extrafield:'\''Field added with custom callback:'\'' + feature.name,phase:undefined,type:undefined}"
}
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"trackId": "genes",
"assemblyNames": ["volvox"],
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"formatDetails": {
"feature": "jexl:{name:'<a href=https://google.com/?q='+feature.name+'>'+feature.name+'</a>',extrafield:'Field added with custom callback:' + feature.name,phase:undefined,type:undefined}"
}
}volvox.sort.gff3.gz is relative to a config.json. Replace it with its URL or its path on this computer.
The <a> markup is needed only because the link text differs from the URL; a
value that is nothing but a URL is linked for you. The slots
(feature, subfeatures, depth, maxDepth) are on the
formatDetails config docs.
How the returned object is applied
The callback's object is shallow-merged onto the feature, and the result drives the panel:
- A new key adds a row.
- An existing key replaces that row's value, core fields included:
{type: undefined}removes the Type row,{name: ...}rewrites the Name row.lengthcounts as one even though the panel computes it fromstart/end. undefinedornullhides the row.subfeaturescan be hidden but not replaced. Reshape each subfeature with thesubfeaturescallback instead; returning a new list is an error.- A non-object return is an error.
"jexl:feature.name"where"jexl:{name:feature.name}"was meant replaces the panel with a message naming the track, or the session configuration, whose callback failed.
The panel's rows and a plugin's extra panels read the merged feature; an extra
panel also gets the original as unformatted. The sequence panel reads only the
original, so a rewritten name or type never reaches its FASTA header, transcript
picker or sequence. A saved session keeps the raw feature and re-runs the
callbacks on load, so editing a track's formatDetails reshapes an open panel
in place.
What a callback can see
featureis the clicked feature, or insubfeaturesthe subfeature being formatted.trackis the track's config, so one session-wide callback can link out per assembly:"jexl:{ncbi:'https://www.ncbi.nlm.nih.gov/gene/?term='+feature.name+'+'+track.assemblyNames[0]}".- In
subfeatures,parentis the feature this one sits in anddepthhow far down, 1 for a gene's transcript and 2 for the transcript's exon, so a transcript row can hold its gene's name:"jexl:{gene:parent.name}".
Values are HTML, and bare URLs become links
Every value passes through an HTML sanitizer, so <b>, <a> and <table>
render as markup, and a value that is not recognizable HTML is escaped (a VCF
<TRA> allele still reads as <TRA>). A value that is just a URL becomes a
link on its own; the
cookbook's details recipe links a gene
to NCBI that way.
Static fields, depth and maxDepth
Only a string starting with jexl: is evaluated, so a field that is the same on
every feature is written as a plain object. A GFF3 gene nests three levels deep
(gene, mRNA, then exon and CDS), and two slots bound how far the panel goes:
depthbounds thesubfeaturescallback. At1it reformats only the transcript rows.maxDepthbounds the panel. At1it shows the transcript cards but not the exon and CDS cards inside them, formatted or not.
Goes in the tracks array of config.json. See Tracks.
{
"trackId": "genes_transcripts_only",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatDetails": {
"feature": {
"Source": "GENCODE v44",
"Contact": "helpdesk@example.org",
"phase": null
},
"subfeatures": "jexl:{Transcript:feature.name, phase:undefined}",
"depth": 1,
"maxDepth": 1
}
}jbrowse add-track-json '{
"trackId": "genes_transcripts_only",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatDetails": {
"feature": {
"Source": "GENCODE v44",
"Contact": "helpdesk@example.org",
"phase": null
},
"subfeatures": "jexl:{Transcript:feature.name, phase:undefined}",
"depth": 1,
"maxDepth": 1
}
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"trackId": "genes_transcripts_only",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatDetails": {
"feature": {
"Source": "GENCODE v44",
"Contact": "helpdesk@example.org",
"phase": null
},
"subfeatures": "jexl:{Transcript:feature.name, phase:undefined}",
"depth": 1,
"maxDepth": 1
}
}volvox.sort.gff3.gz is relative to a config.json. Replace it with its URL or its path on this computer.
Session-wide formatDetails
The feature, subfeatures, depth and maxDepth slots also exist under
configuration.formatDetails, applied to every
track:
{
"configuration": {
"formatDetails": {
"feature": "jexl:{Assembly:'hg19', score:undefined}",
"subfeatures": "jexl:{Assembly:'hg19'}",
"maxDepth": 2
}
}
}Where a track sets the same slot, feature and subfeatures objects are
merged (the track's keys over the session's) and depth/maxDepth
override (the track's value wins).
Complex logic goes in a jexl function
Register a function from a small plugin, as the
no-build plugin tutorial
shows, and call it from the slot:
"feature": "jexl:{name:formatName(feature)}". The function can return a whole
object (many attributes relabeled at once) or one value (a dbxref turned into
a link).
The feature a formatDetails callback receives is a plain object read from the
serialized session, so use property access (feature.start);
feature.get('start') fails here. See
property access vs get().
The About track dialog
formatAbout reshapes the "About track" dialog the same way, on the track or
session-wide as configuration.formatAbout. The
callback's variable is config, the track's own configuration:
Goes in the tracks array of config.json. See Tracks.
{
"trackId": "genes",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatAbout": {
"hideUris": true,
"config": "jexl:{Source:'GENCODE v44',adapter:undefined}"
}
}jbrowse add-track-json '{
"trackId": "genes",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatAbout": {
"hideUris": true,
"config": "jexl:{Source:'\''GENCODE v44'\'',adapter:undefined}"
}
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"trackId": "genes",
"name": "Genes",
"uri": "volvox.sort.gff3.gz",
"assemblyNames": ["volvox"],
"formatAbout": {
"hideUris": true,
"config": "jexl:{Source:'GENCODE v44',adapter:undefined}"
}
}volvox.sort.gff3.gz is relative to a config.json. Replace it with its URL or its path on this computer.
hideUrisdrops every file location from the dialog only;config.jsonstill has them. A session-widetruecannot be turned back on by a track.configmerges over the config shown, exactly asformatDetails.featuredoes.
Adding a panel or replacing the widget
To add a section of your own or replace the widget wholesale, a plugin uses two extension points:
Core-extraFeaturePanelappends a React component below the built-in sectionsCore-replaceWidgetwraps or replaces the whole feature-details widget
See also
- Config guide: Using jexl callbacks
- Config guide: Customizing feature colors
- Developer guide: Extension points