Browse Source

basic uncertainty color/size theme

Alexander Rose 6 years ago
parent
commit
fe9e6a17ad

+ 2 - 0
src/mol-theme/color.ts

@@ -26,6 +26,7 @@ import { ShapeGroupColorThemeProvider } from './color/shape-group';
 import { UnitIndexColorThemeProvider } from './color/unit-index';
 import { ScaleLegend } from 'mol-util/color/scale';
 import { TableLegend } from 'mol-util/color/tables';
+import { UncertaintyColorThemeProvider } from './color/uncertainty';
 
 export type LocationColor = (location: Location, isSecondary: boolean) => Color
 
@@ -73,6 +74,7 @@ export const BuiltInColorThemes = {
     'secondary-structure': SecondaryStructureColorThemeProvider,
     'sequence-id': SequenceIdColorThemeProvider,
     'shape-group': ShapeGroupColorThemeProvider,
+    'uncertainty': UncertaintyColorThemeProvider,
     'unit-index': UnitIndexColorThemeProvider,
     'uniform': UniformColorThemeProvider,
 }

+ 70 - 0
src/mol-theme/color/uncertainty.ts

@@ -0,0 +1,70 @@
+/**
+ * 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 { ColorListName, ColorListOptions } from 'mol-util/color/scale';
+
+const DefaultUncertaintyColor = Color(0xffff99)
+const Description = `Assigns a color based on the uncertainty of an element's position, , e.g. B-factor or RMSF, depending on the data availability and experimental technique.`
+
+export const UncertaintyColorThemeParams = {
+    domain: PD.Interval([0, 100]),
+    list: PD.ColorScale<ColorListName>('RedWhiteBlue', ColorListOptions),
+}
+export type UncertaintyColorThemeParams = typeof UncertaintyColorThemeParams
+export function getUncertaintyColorThemeParams(ctx: ThemeDataContext) {
+    return UncertaintyColorThemeParams // TODO return copy
+}
+
+export function getUncertainty(unit: Unit, element: ElementIndex): number {
+    if (Unit.isAtomic(unit)) {
+        return unit.model.atomicConformation.B_iso_or_equiv.value(element)
+    } else if (Unit.isSpheres(unit)) {
+        return unit.model.coarseConformation.spheres.rmsf[element]
+    } else {
+        return 0
+    }
+}
+
+export function UncertaintyColorTheme(ctx: ThemeDataContext, props: PD.Values<UncertaintyColorThemeParams>): ColorTheme<UncertaintyColorThemeParams> {
+    const scale = ColorScale.create({
+        domain: props.domain,
+        listOrName: props.list,
+    })
+
+    // TODO calc domain based on data, set min/max as 10/90 percentile to be robust against outliers
+
+    function color(location: Location): Color {
+        if (StructureElement.isLocation(location)) {
+            return scale.color(getUncertainty(location.unit, location.element))
+        } else if (Link.isLocation(location)) {
+            return scale.color(getUncertainty(location.aUnit, location.aUnit.elements[location.aIndex]))
+        }
+        return DefaultUncertaintyColor
+    }
+
+    return {
+        factory: UncertaintyColorTheme,
+        granularity: 'group',
+        color,
+        props,
+        description: Description,
+        legend: scale ? scale.legend : undefined
+    }
+}
+
+export const UncertaintyColorThemeProvider: ColorTheme.Provider<UncertaintyColorThemeParams> = {
+    label: 'Uncertainty',
+    factory: UncertaintyColorTheme,
+    getParams: getUncertaintyColorThemeParams,
+    defaultValues: PD.getDefaultValues(UncertaintyColorThemeParams),
+    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
+}

+ 3 - 1
src/mol-theme/size.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,6 +11,7 @@ import { ThemeDataContext, ThemeRegistry, ThemeProvider } from 'mol-theme/theme'
 import { PhysicalSizeThemeProvider } from './size/physical';
 import { deepEqual } from 'mol-util';
 import { ShapeGroupSizeThemeProvider } from './size/shape-group';
+import { UncertaintySizeThemeProvider } from './size/uncertainty';
 
 export { SizeTheme }
 interface SizeTheme<P extends PD.Params> {
@@ -44,6 +45,7 @@ namespace SizeTheme {
 export const BuiltInSizeThemes = {
     'physical': PhysicalSizeThemeProvider,
     'shape-group': ShapeGroupSizeThemeProvider,
+    'uncertainty': UncertaintySizeThemeProvider,
     'uniform': UniformSizeThemeProvider
 }
 export type BuiltInSizeThemeName = keyof typeof BuiltInSizeThemes

+ 61 - 0
src/mol-theme/size/uncertainty.ts

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure';
+import { Location } from 'mol-model/location';
+import { SizeTheme } from '../size';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+
+const Description = `Assigns a size reflecting the uncertainty of an element's position, e.g. B-factor or RMSF, depending on the data availability and experimental technique.`
+
+export const UncertaintySizeThemeParams = {
+    bfactorFactor: PD.Numeric(0.1, { min: 0, max: 1, step: 0.01 }),
+    rmsfFactor: PD.Numeric(0.05, { min: 0, max: 1, step: 0.01 }),
+    baseSize: PD.Numeric(0.2, { min: 0, max: 2, step: 0.1 }),
+}
+export type UncertaintySizeThemeParams = typeof UncertaintySizeThemeParams
+export function getUncertaintySizeThemeParams(ctx: ThemeDataContext) {
+    return UncertaintySizeThemeParams // TODO return copy
+}
+
+export function getUncertainty(unit: Unit, element: ElementIndex, props: PD.Values<UncertaintySizeThemeParams>): number {
+    if (Unit.isAtomic(unit)) {
+        return unit.model.atomicConformation.B_iso_or_equiv.value(element) * props.bfactorFactor
+    } else if (Unit.isSpheres(unit)) {
+        return unit.model.coarseConformation.spheres.rmsf[element] * props.rmsfFactor
+    } else {
+        return 0
+    }
+}
+
+export function UncertaintySizeTheme(ctx: ThemeDataContext, props: PD.Values<UncertaintySizeThemeParams>): SizeTheme<UncertaintySizeThemeParams> {
+    function size(location: Location): number {
+        let size = props.baseSize
+        if (StructureElement.isLocation(location)) {
+            size += getUncertainty(location.unit, location.element, props)
+        } else if (Link.isLocation(location)) {
+            size += getUncertainty(location.aUnit, location.aUnit.elements[location.aIndex], props)
+        }
+        return size
+    }
+
+    return {
+        factory: UncertaintySizeTheme,
+        granularity: 'group',
+        size,
+        props,
+        description: Description
+    }
+}
+
+export const UncertaintySizeThemeProvider: SizeTheme.Provider<UncertaintySizeThemeParams> = {
+    label: 'Uncertainty',
+    factory: UncertaintySizeTheme,
+    getParams: getUncertaintySizeThemeParams,
+    defaultValues: PD.getDefaultValues(UncertaintySizeThemeParams),
+    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure // TODO check if the structure has Uncertainty (B-factor, RMSF, ...) values
+}