diff --git a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts index dcf176ba3d1fef8188b3b2886be11e7d46beb4c6..82387af83fe0a284eebadd7a38b129219606807e 100644 --- a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts @@ -54,11 +54,11 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, struct while (residueIt.hasNext) { const { index: residueIndex } = residueIt.move(); - const cc = chemicalComponentMap.get(label_comp_id.value(residueIndex)) + let compId = label_comp_id.value(residueIndex) + const cc = chemicalComponentMap.get(compId) const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown if (isNucleic(moleculeType)) { - let compId = label_comp_id.value(residueIndex) const parentId = modifiedResidues.parentId.get(compId) if (parentId !== undefined) compId = parentId let idx1 = -1, idx2 = -1, idx3 = -1, idx4 = -1, idx5 = -1, idx6 = -1 diff --git a/src/mol-view/theme/color.ts b/src/mol-view/theme/color.ts index 7b1f0e4d2f6275d31d13506303a5a512db649a1a..aac704dd314321c5bc8b169fb036348db8e74378 100644 --- a/src/mol-view/theme/color.ts +++ b/src/mol-view/theme/color.ts @@ -7,6 +7,7 @@ import { Color } from 'mol-util/color'; import { Structure } from 'mol-model/structure'; import { Location } from 'mol-model/location'; +import { ColorType } from 'mol-geo/util/color-data'; import { ElementIndexColorTheme } from './color/element-index'; import { CarbohydrateSymbolColorTheme } from './color/carbohydrate-symbol'; @@ -17,7 +18,7 @@ import { UniformColorTheme } from './color/uniform'; import { CrossLinkColorTheme } from './color/cross-link'; import { ShapeGroupColorTheme } from './color/shape-group'; import { CustomColorTheme } from './color/custom'; -import { ColorType } from 'mol-geo/util/color-data'; +import { ResidueNameColorTheme } from './color/residue-name'; export type LocationColor = (location: Location, isSecondary: boolean) => Color @@ -53,6 +54,7 @@ export function ColorTheme(props: ColorThemeProps): ColorTheme { case 'cross-link': return CrossLinkColorTheme(props) case 'chain-id': return ChainIdColorTheme(props) case 'element-symbol': return ElementSymbolColorTheme(props) + case 'residue-name': return ResidueNameColorTheme(props) case 'unit-index': return UnitIndexColorTheme(props) case 'uniform': return UniformColorTheme(props) case 'shape-group': return ShapeGroupColorTheme(props) @@ -77,6 +79,7 @@ export const ColorThemeInfo = { 'cross-link': {}, 'chain-id': {}, 'element-symbol': {}, + 'residue-name': {}, 'unit-index': {}, 'uniform': {}, 'shape-group': {}, diff --git a/src/mol-view/theme/color/element-symbol.ts b/src/mol-view/theme/color/element-symbol.ts index c73ae2d46280e1491535b2d6d79c98a328760d49..e382f14d87f48d496faaa8eb2c0e794bbc04aa5c 100644 --- a/src/mol-view/theme/color/element-symbol.ts +++ b/src/mol-view/theme/color/element-symbol.ts @@ -20,7 +20,7 @@ const Description = 'Assigns a color to every atom according to its chemical ele export function elementSymbolColor(element: ElementSymbol): Color { const c = (ElementSymbolColors as { [k: string]: Color })[element]; - return c === void 0 ? DefaultElementSymbolColor : c + return c === undefined ? DefaultElementSymbolColor : c } export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme { diff --git a/src/mol-view/theme/color/residue-name.ts b/src/mol-view/theme/color/residue-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..02f2425fbc446cc9ca174ae743073b9b047c2501 --- /dev/null +++ b/src/mol-view/theme/color/residue-name.ts @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Color, ColorMap } from 'mol-util/color'; +import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure'; +import { Location } from 'mol-model/location'; +import { ColorThemeProps, ColorTheme, TableLegend } from '../color'; + +// protein colors from Jmol http://jmol.sourceforge.net/jscolors/ +const ResidueNameColors = ColorMap({ + // standard amino acids + 'ALA': 0x8CFF8C, + 'ARG': 0x00007C, + 'ASN': 0xFF7C70, + 'ASP': 0xA00042, + 'CYS': 0xFFFF70, + 'GLN': 0xFF4C4C, + 'GLU': 0x660000, + 'GLY': 0xEEEEEE, + 'HIS': 0x7070FF, + 'ILE': 0x004C00, + 'LEU': 0x455E45, + 'LYS': 0x4747B8, + 'MET': 0xB8A042, + 'PHE': 0x534C52, + 'PRO': 0x525252, + 'SER': 0xFF7042, + 'THR': 0xB84C00, + 'TRP': 0x4F4600, + 'TYR': 0x8C704C, + 'VAL': 0xFF8CFF, + + // rna bases + 'A': 0xDC143C, // Crimson Red + 'G': 0x32CD32, // Lime Green + 'I': 0x9ACD32, // Yellow Green + 'C': 0xFFD700, // Gold Yellow + 'T': 0x4169E1, // Royal Blue + 'U': 0x40E0D0, // Turquoise Cyan + + // dna bases + 'DA': 0xDC143C, + 'DG': 0x32CD32, + 'DI': 0x9ACD32, + 'DC': 0xFFD700, + 'DT': 0x4169E1, + 'DU': 0x40E0D0, + + // peptide bases + 'APN': 0xDC143C, + 'GPN': 0x32CD32, + 'CPN': 0xFFD700, + 'TPN': 0x4169E1, +}) + +const DefaultResidueNameColor = Color(0xFF00FF) +const Description = 'Assigns a color to every residue according to its name.' + +export function residueNameColor(residueName: string): Color { + const c = (ResidueNameColors as { [k: string]: Color })[residueName]; + return c === undefined ? DefaultResidueNameColor : c +} + +function getAtomicCompId(unit: Unit.Atomic, element: ElementIndex) { + const { modifiedResidues } = unit.model.properties + const compId = unit.model.atomicHierarchy.residues.auth_comp_id.value(unit.residueIndex[element]) + const parentId = modifiedResidues.parentId.get(compId) + return parentId === undefined ? compId : parentId +} + +function getCoarseCompId(unit: Unit.Spheres | Unit.Gaussians, element: ElementIndex) { + const seqIdBegin = unit.coarseElements.seq_id_begin.value(element) + const seqIdEnd = unit.coarseElements.seq_id_end.value(element) + if (seqIdBegin === seqIdEnd) { + const { modifiedResidues } = unit.model.properties + const entityKey = unit.coarseElements.entityKey[element] + const seq = unit.model.sequence.byEntityKey[entityKey] + let compId = seq.compId.value(seqIdBegin - 1) // 1-indexed + const parentId = modifiedResidues.parentId.get(compId) + return parentId === undefined ? compId : parentId + } +} + +export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme { + function color(location: Location): Color { + if (StructureElement.isLocation(location)) { + if (Unit.isAtomic(location.unit)) { + return residueNameColor(getAtomicCompId(location.unit, location.element)) + } else { + const compId = getCoarseCompId(location.unit, location.element) + if (compId) return residueNameColor(compId) + } + } else if (Link.isLocation(location)) { + if (Unit.isAtomic(location.aUnit)) { + return residueNameColor(getAtomicCompId(location.aUnit, location.aUnit.elements[location.aIndex])) + } else { + const compId = getCoarseCompId(location.aUnit, location.aUnit.elements[location.aIndex]) + if (compId) return residueNameColor(compId) + } + } + return DefaultResidueNameColor + } + + return { + granularity: 'group', + color, + description: Description, + legend: TableLegend(Object.keys(ResidueNameColors).map(name => { + return [name, (ResidueNameColors as any)[name] as Color] as [string, Color] + }).concat([[ 'Unknown', DefaultResidueNameColor ]])) + } +} \ No newline at end of file