secondary-structure.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Color, ColorMap } from '../../mol-util/color';
  7. import { StructureElement, Unit, Bond, ElementIndex } from '../../mol-model/structure';
  8. import { Location } from '../../mol-model/location';
  9. import { ColorTheme } from '../color';
  10. import { SecondaryStructureType, MoleculeType } from '../../mol-model/structure/model/types';
  11. import { getElementMoleculeType } from '../../mol-model/structure/util';
  12. import { ParamDefinition as PD } from '../../mol-util/param-definition'
  13. import { ThemeDataContext } from '../theme';
  14. import { TableLegend } from '../../mol-util/legend';
  15. import { SecondaryStructureProvider, SecondaryStructureValue } from '../../mol-model-props/computed/secondary-structure';
  16. import { getAdjustedColorMap } from '../../mol-util/color/color';
  17. import { CustomProperty } from '../../mol-model-props/common/custom-property';
  18. // from Jmol http://jmol.sourceforge.net/jscolors/ (shapely)
  19. const SecondaryStructureColors = ColorMap({
  20. 'alphaHelix': 0xFF0080,
  21. 'threeTenHelix': 0xA00080,
  22. 'piHelix': 0x600080,
  23. 'betaTurn': 0x6080FF,
  24. 'betaStrand': 0xFFC800,
  25. 'coil': 0xFFFFFF,
  26. 'bend': 0x66D8C9 /* biting original color used 0x00FF00 */,
  27. 'turn': 0x00B266,
  28. 'dna': 0xAE00FE,
  29. 'rna': 0xFD0162,
  30. 'carbohydrate': 0xA6A6FA
  31. })
  32. export type SecondaryStructureColors = typeof SecondaryStructureColors
  33. const DefaultSecondaryStructureColor = Color(0x808080)
  34. const Description = 'Assigns a color based on the type of secondary structure and basic molecule type.'
  35. export const SecondaryStructureColorThemeParams = {
  36. saturation: PD.Numeric(-1, { min: -6, max: 6, step: 0.1 }),
  37. lightness: PD.Numeric(0, { min: -6, max: 6, step: 0.1 })
  38. }
  39. export type SecondaryStructureColorThemeParams = typeof SecondaryStructureColorThemeParams
  40. export function getSecondaryStructureColorThemeParams(ctx: ThemeDataContext) {
  41. return SecondaryStructureColorThemeParams // TODO return copy
  42. }
  43. export function secondaryStructureColor(colorMap: SecondaryStructureColors, unit: Unit, element: ElementIndex, computedSecondaryStructure?: SecondaryStructureValue): Color {
  44. let secStrucType = SecondaryStructureType.create(SecondaryStructureType.Flag.None)
  45. if (computedSecondaryStructure && Unit.isAtomic(unit)) {
  46. const secondaryStructure = computedSecondaryStructure.get(unit.invariantId)
  47. if (secondaryStructure) secStrucType = secondaryStructure.type[secondaryStructure.getIndex(unit.residueIndex[element])]
  48. }
  49. if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.Helix)) {
  50. if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.Helix3Ten)) {
  51. return colorMap.threeTenHelix
  52. } else if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.HelixPi)) {
  53. return colorMap.piHelix
  54. }
  55. return colorMap.alphaHelix
  56. } else if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.Beta)) {
  57. return colorMap.betaStrand
  58. } else if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.Bend)) {
  59. return colorMap.bend
  60. } else if (SecondaryStructureType.is(secStrucType, SecondaryStructureType.Flag.Turn)) {
  61. return colorMap.turn
  62. } else {
  63. const moleculeType = getElementMoleculeType(unit, element)
  64. if (moleculeType === MoleculeType.DNA) {
  65. return colorMap.dna
  66. } else if (moleculeType === MoleculeType.RNA) {
  67. return colorMap.rna
  68. } else if (moleculeType === MoleculeType.Saccharide) {
  69. return colorMap.carbohydrate
  70. } else if (moleculeType === MoleculeType.Protein) {
  71. return colorMap.coil
  72. }
  73. }
  74. return DefaultSecondaryStructureColor
  75. }
  76. export function SecondaryStructureColorTheme(ctx: ThemeDataContext, props: PD.Values<SecondaryStructureColorThemeParams>): ColorTheme<SecondaryStructureColorThemeParams> {
  77. const computedSecondaryStructure = ctx.structure && SecondaryStructureProvider.get(ctx.structure)
  78. const contextHash = computedSecondaryStructure && computedSecondaryStructure.version
  79. const colorMap = getAdjustedColorMap(SecondaryStructureColors, props.saturation, props.lightness)
  80. function color(location: Location): Color {
  81. if (StructureElement.Location.is(location)) {
  82. return secondaryStructureColor(colorMap, location.unit, location.element, computedSecondaryStructure?.value)
  83. } else if (Bond.isLocation(location)) {
  84. return secondaryStructureColor(colorMap, location.aUnit, location.aUnit.elements[location.aIndex], computedSecondaryStructure?.value)
  85. }
  86. return DefaultSecondaryStructureColor
  87. }
  88. return {
  89. factory: SecondaryStructureColorTheme,
  90. granularity: 'group',
  91. color,
  92. props,
  93. contextHash,
  94. description: Description,
  95. legend: TableLegend(Object.keys(SecondaryStructureColors).map(name => {
  96. return [name, (SecondaryStructureColors as any)[name] as Color] as [string, Color]
  97. }).concat([[ 'Other', DefaultSecondaryStructureColor ]]))
  98. }
  99. }
  100. export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<SecondaryStructureColorThemeParams> = {
  101. label: 'Secondary Structure',
  102. category: ColorTheme.Category.Basic,
  103. factory: SecondaryStructureColorTheme,
  104. getParams: getSecondaryStructureColorThemeParams,
  105. defaultValues: PD.getDefaultValues(SecondaryStructureColorThemeParams),
  106. isApplicable: (ctx: ThemeDataContext) => !!ctx.structure,
  107. ensureCustomProperties: (ctx: CustomProperty.Context, data: ThemeDataContext) => {
  108. return data.structure ? SecondaryStructureProvider.attach(ctx, data.structure) : Promise.resolve()
  109. }
  110. }