Multi-row feature track
The multi-row feature display splits one interval file into a stack of labeled rows, one per value of a column you nominate, and paints each feature as a colored block. A cohort of per-sample interval data (chromatin states per cell type, copy number per tumor, ancestry per haplotype, genotype per strain) becomes a single track with one config, one adapter, and one fetch.
Any BED, BigBed, GFF3, or GTF track can be switched to it from the track menu: Display types → Multi-row feature display (painting).
Turning a feature track into rows
Picking it from Display types shows the rows right away, split on whichever
column the file turns out to have: a RepeatMasker table opens as ~20 rows of
repClass, and anything else falls back to the name column. Which column
assigns a feature to a row is then One row per… in the same track menu,
which lists the attribute names the loaded features have — so RepeatMasker also
offers repFamily and name beside the class it started on. Repartitioning
leaves a saved row order, its labels and colors and a clustering run in place:
they name rows by value, so they sit idle under the new partition and come back
with the field. Hidden legend categories clear.
To fix the column in config, set
rows in the track
config:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "chromhmm",
"name": "ChromHMM states",
"uri": "https://example.com/chromhmm.bed.gz",
"assemblyNames": ["hg19"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "chromhmm-LinearMultiRowFeatureDisplay",
"rows": "cellType"
}
]
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "chromhmm",
"name": "ChromHMM states",
"uri": "https://example.com/chromhmm.bed.gz",
"assemblyNames": ["hg19"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "chromhmm-LinearMultiRowFeatureDisplay",
"rows": "cellType"
}
]
}'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:
{
"type": "FeatureTrack",
"trackId": "chromhmm",
"name": "ChromHMM states",
"uri": "https://example.com/chromhmm.bed.gz",
"assemblyNames": ["hg19"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "chromhmm-LinearMultiRowFeatureDisplay",
"rows": "cellType"
}
]
}rows names the feature attribute whose value assigns a feature to a row.
Features sharing a value stack into the same row, and the value becomes the row
label.
The rows are discovered from the values the loaded region holds, so a file that gains a sample or a category needs no config change, and a region missing one has no row for it.
Partitioning with a jexl expression
A file can have the category without a column for it, in which case rows takes
a jexl expression instead of an attribute name.
UCSC's bigRmskBed is the common case: the repeat class is a suffix on the name
(L1HS#LINE/L1), so an attribute lookup splits on the full repeat name, which
is thousands of rows rather than twenty.
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "genark_rmsk",
"name": "RepeatMasker by class",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/019/238/085/GCF_019238085.1/bbi/GCF_019238085.1_USGS_WTPT01.rmsk.bb",
"assemblyNames": ["GCF_019238085.1"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "genark_rmsk-LinearMultiRowFeatureDisplay",
"rows": "jexl:split(split(feature.name,'#')[1],'/')[0]"
}
]
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "genark_rmsk",
"name": "RepeatMasker by class",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/019/238/085/GCF_019238085.1/bbi/GCF_019238085.1_USGS_WTPT01.rmsk.bb",
"assemblyNames": ["GCF_019238085.1"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "genark_rmsk-LinearMultiRowFeatureDisplay",
"rows": "jexl:split(split(feature.name,'\''#'\'')[1],'\''/'\'')[0]"
}
]
}'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:
{
"type": "FeatureTrack",
"trackId": "genark_rmsk",
"name": "RepeatMasker by class",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/019/238/085/GCF_019238085.1/bbi/GCF_019238085.1_USGS_WTPT01.rmsk.bb",
"assemblyNames": ["GCF_019238085.1"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "genark_rmsk-LinearMultiRowFeatureDisplay",
"rows": "jexl:split(split(feature.name,'#')[1],'/')[0]"
}
]
}The final [0] selects class; swap it for [1] to split by family.
The multi-row display isn't the track's default, so it needs an explicit
displays entry rather than the displayDefaults shorthand (whose color
would also reach the default display).
Preparing the file
The input is one file holding every sample's intervals, with a column naming the
sample. For BED, name the columns with a #-prefixed header line so the adapter
picks them up, then bgzip and tabix as usual:
#chrom chromStart chromEnd name score strand thickStart thickEnd itemRgb cellType
chr1 10000 10600 15_Repetitive/CNV 0 . 10000 10600 245,245,245 GM12878
chr1 10000 10600 15_Repetitive/CNV 0 . 10000 10600 245,245,245 K562Any extra column works the same way, so rows can be sample, cellType,
strain, haplotype, or whatever you called it. GFF3/GTF attributes and BigBed
extra fields are addressed by name identically.
Coloring the blocks
Four sources of color, in precedence order:
rowColorgives a color per row as pairs, the row values indomainand their colors inrange, or with afielda color per value of a row attribute such as itsrowGroupsgroup. Use it when the row identity is the signal (one color per population, per treatment arm).coloris a per- feature fill: a CSS color, or a field whose values each take a color through a scale — a color per value, a color per interval between cut points, or a gradient — with a key naming them.itemRgbis honored automatically. A BED9 that already has per-feature colors (ChromHMM state colors, for one) paints correctly with no color configuration.- Otherwise each row is auto-assigned a distinct color from a categorical palette.
Binning a numeric column onto a diverging scale is the common case, e.g. segment
mean copy number, with labels naming each interval in the key:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "tcga_brca_cnv",
"name": "TCGA-BRCA copy number",
"uri": "https://jbrowse.org/demos/tcga/tcga_brca_cnv.bed.gz",
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "tcga_brca_cnv-LinearMultiRowFeatureDisplay",
"rows": "sample",
"color": {
"field": "segmean",
"scale": "threshold",
"domain": ["-1", "-0.3", "0.3", "1"],
"range": ["#2166ac", "#92c5de", "#f7f7f7", "#f4a582", "#b2182b"],
"labels": [
"Deep loss (log2 < -1)",
"Loss",
"Balanced",
"Gain",
"Amplification (log2 > 1)"
],
"title": "Copy number (log2)"
}
}
]
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "tcga_brca_cnv",
"name": "TCGA-BRCA copy number",
"uri": "https://jbrowse.org/demos/tcga/tcga_brca_cnv.bed.gz",
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "tcga_brca_cnv-LinearMultiRowFeatureDisplay",
"rows": "sample",
"color": {
"field": "segmean",
"scale": "threshold",
"domain": ["-1", "-0.3", "0.3", "1"],
"range": ["#2166ac", "#92c5de", "#f7f7f7", "#f4a582", "#b2182b"],
"labels": [
"Deep loss (log2 < -1)",
"Loss",
"Balanced",
"Gain",
"Amplification (log2 > 1)"
],
"title": "Copy number (log2)"
}
}
]
}'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:
{
"type": "FeatureTrack",
"trackId": "tcga_brca_cnv",
"name": "TCGA-BRCA copy number",
"uri": "https://jbrowse.org/demos/tcga/tcga_brca_cnv.bed.gz",
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"displayId": "tcga_brca_cnv-LinearMultiRowFeatureDisplay",
"rows": "sample",
"color": {
"field": "segmean",
"scale": "threshold",
"domain": ["-1", "-0.3", "0.3", "1"],
"range": ["#2166ac", "#92c5de", "#f7f7f7", "#f4a582", "#b2182b"],
"labels": [
"Deep loss (log2 < -1)",
"Loss",
"Balanced",
"Gain",
"Amplification (log2 > 1)"
],
"title": "Copy number (log2)"
}
}
]
}Show... → Show legend keys the colors actually present, and the
Categories submenu beside it hides individual categories, so you can drop
the states or classes you aren't reading and leave the rest painted. The submenu
counts what is hidden and offers Show all categories to put them back.
color.domain sets the order those rows read in — the values it lists first,
the rest sorted — the same word and rule domain orders the track's rows by.
You can also pick a color for single rows under Color rows by → Each row in
Edit colors/arrangement..., which writes each as a rowColor entry and
applies at render time, with no refetch.
Row height
The track menu's Row height offers Squeeze to fit view (the default: rows divide the track height, so adding samples shrinks the rows), Normal, and Compact. With fit, drag the track taller to give a deep cohort more room per row.
Ordering and clustering rows
Rows start sorted by value, digits by magnitude, with the row of features with no value last. Three ways to change that:
- Edit colors/arrangement... reorders, relabels or hand-picks rows in a
dialog, and
rows.domainpins an explicit order in config: the values it lists lead, and the rest sort. - Right-click a position and choose Sort rows by color here to order rows by the value each has at that exact base, the analogue of an alignments track's sort-by-base. Rows sharing a value become contiguous blocks, turning a QTL painting at its peak into a clean split by allele.
- Clustering → Cluster rows by similarity... reorders rows so that samples with similar paintings sit together, and draws a dendrogram in the sidebar. See Clustering rows.
All three write the track's
rows setting, so undo
reaches an arrangement, a shared session contains it, and it survives turning
the track off and on. Reset row order appears in the track menu once any of
the three has run, and returns the rows, their labels and their colors to what
the config declares.
rowGroups tags
each row with a group, the first { match, group } entry whose regex its name
matches, and
facet: "group" stacks
the rows in bands by it, each band named in a strip beside the dendrogram and
keeping its rows in their arranged order; clustering then runs within each band.
A group carries no color of its own; rowColor colors the groups:
{
"rowGroups": [
{ "match": "^CLUP", "group": "Wolf" },
{ "match": "^CLAT", "group": "Coyote" }
],
"facet": "group",
"rowColor": {
"field": "group",
"domain": ["Wolf", "Coyote"],
"range": ["rgb(27,120,55)", "rgb(224,130,20)"]
}
}Bands carry a group by position, which stays readable over many groups where colors alone blur together, so a long list of groups reads best faceted, with the colors as the second cue.
Show... → Show tree toggles the dendrogram once one has been computed, and Show... → Show row labels the labels beside it, which are useful with no clustering run.
A row with a color of its own, from
rowColor by its
name or by an attribute such as its group, draws it as a bar at the left of its
label, so a row can be found by color. A row with no value of that attribute,
such as one no rowGroups entry matches, takes no color unless domain pairs
"" with one. On a track colored per feature (an itemRgb painting, a jexl
color slot) the bar is the only place a row's color shows.
Worked examples
Each of these builds the input file and the track config end to end:
- ChromHMM chromatin states - many cell types from one merged BED, colored by
itemRgb - CNV cohort (TCGA) - a thousand tumors, colored by the interval a numeric column falls in
- QTL mapping (BXD mice) - strain genotype painting beside a QTL Manhattan plot, sorted at the peak
- Phased trio analysis (1000 Genomes) - IBD blocks and local ancestry per haplotype
See also
- User guide: Quantitative track - the same one-row-per-sample idea for signal data
- User guide: Multi-sample variant display
- Config guide: Customizing feature colors
- Reference: LinearMultiRowFeatureDisplay config schema
- ROW_HEIGHT_AND_FIT.md
— the same Row height menu across every multi-row display: the slot whose
0means fit, and the resolved getter beside it that other plugins read