|
@@ -0,0 +1,107 @@
|
|
|
+/**
|
|
|
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
+ *
|
|
|
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
|
+ */
|
|
|
+
|
|
|
+import { Color, ColorScale } from 'mol-util/color';
|
|
|
+import { StructureElement, Unit, Link, 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';
|
|
|
+import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
|
|
|
+
|
|
|
+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.ColorScale<ColorListName>('RedYellowGreen', ColorListOptions),
|
|
|
+ scale: PD.Select('DGwif', [['DGwif', 'DG water-membrane'], ['DGwoct', 'DG water-octanol'], ['Oct-IF', 'DG difference']])
|
|
|
+}
|
|
|
+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) {
|
|
|
+ const { modifiedResidues } = unit.model.properties
|
|
|
+ const compId = unit.model.atomicHierarchy.residues.label_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 HydrophobicityColorTheme(ctx: ThemeDataContext, props: PD.Values<HydrophobicityColorThemeParams>): ColorTheme<HydrophobicityColorThemeParams> {
|
|
|
+ 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,
|
|
|
+ domain: [ max, min ],
|
|
|
+ minLabel: 'Hydrophobic',
|
|
|
+ maxLabel: 'Hydrophilic'
|
|
|
+ })
|
|
|
+
|
|
|
+ function color(location: Location): Color {
|
|
|
+ let compId: string | undefined
|
|
|
+ if (StructureElement.isLocation(location)) {
|
|
|
+ if (Unit.isAtomic(location.unit)) {
|
|
|
+ compId = getAtomicCompId(location.unit, location.element)
|
|
|
+ } else {
|
|
|
+ compId = getCoarseCompId(location.unit, location.element)
|
|
|
+ }
|
|
|
+ } else if (Link.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<HydrophobicityColorThemeParams> = {
|
|
|
+ label: 'Hydrophobicity',
|
|
|
+ factory: HydrophobicityColorTheme,
|
|
|
+ getParams: getHydrophobicityColorThemeParams,
|
|
|
+ defaultValues: PD.getDefaultValues(HydrophobicityColorThemeParams),
|
|
|
+ isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
|
|
+}
|