diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index a76970c184b1b8e2bb52c1f2f6b7b21f2bc58ae3..cab7d59fcd15c3839d33722eed8d6d929908f7ec 100644 --- a/src/mol-theme/color.ts +++ b/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, } diff --git a/src/mol-theme/color/uncertainty.ts b/src/mol-theme/color/uncertainty.ts new file mode 100644 index 0000000000000000000000000000000000000000..857951921bcf5efb4e6e241e2805d4e9c38ff2bb --- /dev/null +++ b/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 +} \ No newline at end of file diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 84adfd7667e8b0ee6de8e63ff7251f23b46a644f..2bed1e52e9307d1ee5d82e0a1db109b485bbdf4b 100644 --- a/src/mol-theme/size.ts +++ b/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 \ No newline at end of file diff --git a/src/mol-theme/size/uncertainty.ts b/src/mol-theme/size/uncertainty.ts new file mode 100644 index 0000000000000000000000000000000000000000..d75a7f4ac7974a0273f98b3604669cb50411d36a --- /dev/null +++ b/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 +} \ No newline at end of file