/** * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { Color, ColorScale } from '../../mol-util/color'; import { StructureElement, Unit, Bond, ElementIndex } from '../../mol-model/structure'; import { Location } from '../../mol-model/location'; import { ColorTheme } from '../color'; import { ParamDefinition as PD } from '../../mol-util/param-definition' import { ThemeDataContext } from '../theme'; import { ResidueHydrophobicity } from '../../mol-model/structure/model/types'; const Description = 'Assigns a color to every amino acid according to the "Experimentally determined hydrophobicity scale for proteins at membrane interfaces" by Wimely and White (doi:10.1038/nsb1096-842).' export const HydrophobicityColorThemeParams = { list: PD.ColorList('red-yellow-green', { presetKind: 'scale' }), scale: PD.Select('DGwif', [['DGwif', 'DG water-membrane'], ['DGwoct', 'DG water-octanol'], ['Oct-IF', 'DG difference']] as const) } export type HydrophobicityColorThemeParams = typeof HydrophobicityColorThemeParams export function getHydrophobicityColorThemeParams(ctx: ThemeDataContext) { return HydrophobicityColorThemeParams // TODO return copy } const scaleIndexMap = { 'DGwif': 0, 'DGwoct': 1, 'Oct-IF': 2 } export function hydrophobicity(compId: string, scaleIndex: number): number { const c = (ResidueHydrophobicity as { [k: string]: number[] })[compId]; return c === undefined ? 0 : c[scaleIndex] } function getAtomicCompId(unit: Unit.Atomic, element: ElementIndex) { return unit.model.atomicHierarchy.residues.label_comp_id.value(unit.residueIndex[element]) } 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 entityKey = unit.coarseElements.entityKey[element] const seq = unit.model.sequence.byEntityKey[entityKey].sequence return seq.compId.value(seqIdBegin - 1) // 1-indexed } } export function HydrophobicityColorTheme(ctx: ThemeDataContext, props: PD.Values): ColorTheme { const scaleIndex = scaleIndexMap[props.scale] // get domain let min = Infinity let max = -Infinity for (const name in ResidueHydrophobicity) { const val = (ResidueHydrophobicity as { [k: string]: number[] })[name][scaleIndex] min = Math.min(min, val) max = Math.max(max, val) } const scale = ColorScale.create({ listOrName: props.list.colors, domain: [ max, min ], minLabel: 'Hydrophobic', maxLabel: 'Hydrophilic' }) function color(location: Location): Color { let compId: string | undefined if (StructureElement.Location.is(location)) { if (Unit.isAtomic(location.unit)) { compId = getAtomicCompId(location.unit, location.element) } else { compId = getCoarseCompId(location.unit, location.element) } } else if (Bond.isLocation(location)) { if (Unit.isAtomic(location.aUnit)) { compId = getAtomicCompId(location.aUnit, location.aUnit.elements[location.aIndex]) } else { compId = getCoarseCompId(location.aUnit, location.aUnit.elements[location.aIndex]) } } return scale.color(compId ? hydrophobicity(compId, scaleIndex) : 0) } return { factory: HydrophobicityColorTheme, granularity: 'group', color, props, description: Description, legend: scale ? scale.legend : undefined } } export const HydrophobicityColorThemeProvider: ColorTheme.Provider = { name: 'hydrophobicity', label: 'Hydrophobicity', category: ColorTheme.Category.Residue, factory: HydrophobicityColorTheme, getParams: getHydrophobicityColorThemeParams, defaultValues: PD.getDefaultValues(HydrophobicityColorThemeParams), isApplicable: (ctx: ThemeDataContext) => !!ctx.structure }