An alignment linked to its structure
The spike and
hemoglobin tutorials
each end on a residueMappings layer, which records the
structure residue for each residue of one row. The viewer below loads one
of those alignments with its layers and the PDB entry the mapping names,
and draws the structure in Mol* under the alignment. A residue hovered in
the alignment lights in the structure, a residue hovered in the structure
lights in the alignment, and the line under the structure reports what
each lookup returned.
What to hover
The spike set opens on the PRRA insert. Hover the SARS-CoV-2 row: each residue from 14 to 1211 reaches chain A of 6VXX at its position plus 19. Residues 681 to 684 report no coordinates, because 6VXX declares structure residues 696 to 707 in its sequence and resolved none of them. Press HR1 and hover row residues 920 to 970: each one lights on chain A, structure residues 939 to 989. Click a cell to turn the camera to that residue, and click a residue in the structure to scroll the alignment to its column.
The hemoglobin set holds one row per species, alpha and beta concatenated. On the Human row, alpha columns reach chain A of 2HHB and beta columns reach chain B. Residues 1 and 143 are the initiator methionines, which the mature chains lack, and report outside the mapped region. The arc track above the alignment joins the residue pairs in contact between the chains.
The built-in control
Each mapping names one row and one chain. Chains B and C of 6VXX are copies of chain A, and chains C and D of 2HHB are copies of A and B, but no mapping names them. A hover on any of them, or on a glycan, heme or water, reports no row maps here and lights nothing in the alignment. The other rows of each alignment report no mapping onto 6VXX or onto 2HHB.
The viewer also checks each mapping against the loaded row and ignores one computed against a different sequence. This page prints each ignored mapping under the status line, and both sets print none.
Color the structure by conservation
The Color the structure by conservation checkbox paints each residue of a mapped chain with the conservation of the alignment column it falls in, the number the Conservation track draws. Five blue steps run from variable to conserved. A residue with no column is grey: the chains no mapping names, the residues outside a mapped region, and a residue in a column that Hide columns has hidden.
The conservation of a column counts the rows on screen. Collapse a clade
in the tree, or show one subtree, and the page repaints the structure from
the rows left. The page walks each residue of the structure through
rowResidue to its row residue, then through
seqPosToVisibleCol to a column, and reads
model.conservation there.
Put it on your own page
The two bridges are one call each way. structureResidue
takes a row and a 1-based residue and returns the structure residue as a
label_seq_id, with its chain and whether it has coordinates.
rowResidue takes a structure residue and its chain and
returns the row and residue, which applyHighlight
draws. Both return undefined where no mapping covers the
residue. model comes from onModel, and
plugin is the Mol* plugin with the structure loaded:
import { MSAViewer } from 'react-msaview'
import {
StructureElement,
StructureProperties,
StructureSelection,
} from 'molstar/lib/mol-model/structure'
import { Script } from 'molstar/lib/mol-script/script'
function residueLoci(structure, labelSeqId, asymId) {
const selection = Script.getStructureSelection(
Q =>
Q.struct.generator.atomGroups({
'chain-test': Q.core.rel.eq([
Q.struct.atomProperty.macromolecular.label_asym_id(),
asymId,
]),
'residue-test': Q.core.rel.eq([
Q.struct.atomProperty.macromolecular.label_seq_id(),
labelSeqId,
]),
}),
structure,
)
return StructureSelection.toLociWithSourceUnits(selection)
}
function onCellHover(cell) {
const hit = cell?.residue && model.structureResidue(cell.row, cell.residue, '6VXX')
const structure =
plugin.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data
const { lociHighlights } = plugin.managers.interactivity
if (hit && structure) {
const loci = residueLoci(structure, hit.position, hit.structure.asymId)
lociHighlights.highlightOnly({ loci }, false)
} else {
lociHighlights.clearHighlights()
}
}
plugin.behaviors.interaction.hover.subscribe(({ current }) => {
const loc = StructureElement.Loci.is(current.loci)
? StructureElement.Loci.getFirstLocation(current.loci)
: undefined
const hit =
loc &&
model.rowResidue(
'6VXX',
StructureProperties.residue.label_seq_id(loc),
StructureProperties.chain.label_asym_id(loc),
)
if (hit) {
model.applyHighlight('structure', [
{ row: hit.rowName, start: hit.seqPos, end: hit.seqPos },
])
} else {
model.clearHighlight('structure')
}
})
<MSAViewer
msaFilehandle={{ uri: 'spike.afa', locationType: 'UriLocation' }}
residueMappings={layers.residueMappings}
onModel={m => {
model = m
}}
onCellHover={onCellHover}
/>
The page loads these files, all served with
Access-Control-Allow-Origin:
- https://gmod.org/JBrowseMSA/demo/data/spike/spike.afa
- https://gmod.org/JBrowseMSA/demo/data/spike/spike.nwk
- https://gmod.org/JBrowseMSA/demo/data/spike/spike-domains.gff
- https://gmod.org/JBrowseMSA/demo/data/spike/spike-layers.json
- https://files.rcsb.org/download/6VXX.cif
- https://gmod.org/JBrowseMSA/demo/data/hemoglobin/hemoglobin.afa
- https://gmod.org/JBrowseMSA/demo/data/hemoglobin/hemoglobin.nwk
- https://gmod.org/JBrowseMSA/demo/data/hemoglobin/hemoglobin-subunits.gff
- https://gmod.org/JBrowseMSA/demo/data/hemoglobin/hemoglobin-layers.json
- https://files.rcsb.org/download/2HHB.cif