residue-name.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * Copyright (c) 2018 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, Link, ElementIndex } from 'mol-model/structure';
  8. import { Location } from 'mol-model/location';
  9. import { ColorTheme } from '../color';
  10. import { ParamDefinition as PD } from 'mol-util/param-definition'
  11. import { ThemeDataContext } from '../theme';
  12. import { TableLegend } from 'mol-util/color/tables';
  13. // protein colors from Jmol http://jmol.sourceforge.net/jscolors/
  14. const ResidueNameColors = ColorMap({
  15. // standard amino acids
  16. 'ALA': 0x8CFF8C,
  17. 'ARG': 0x00007C,
  18. 'ASN': 0xFF7C70,
  19. 'ASP': 0xA00042,
  20. 'CYS': 0xFFFF70,
  21. 'GLN': 0xFF4C4C,
  22. 'GLU': 0x660000,
  23. 'GLY': 0xEEEEEE,
  24. 'HIS': 0x7070FF,
  25. 'ILE': 0x004C00,
  26. 'LEU': 0x455E45,
  27. 'LYS': 0x4747B8,
  28. 'MET': 0xB8A042,
  29. 'PHE': 0x534C52,
  30. 'PRO': 0x525252,
  31. 'SER': 0xFF7042,
  32. 'THR': 0xB84C00,
  33. 'TRP': 0x4F4600,
  34. 'TYR': 0x8C704C,
  35. 'VAL': 0xFF8CFF,
  36. // rna bases
  37. 'A': 0xDC143C, // Crimson Red
  38. 'G': 0x32CD32, // Lime Green
  39. 'I': 0x9ACD32, // Yellow Green
  40. 'C': 0xFFD700, // Gold Yellow
  41. 'T': 0x4169E1, // Royal Blue
  42. 'U': 0x40E0D0, // Turquoise Cyan
  43. // dna bases
  44. 'DA': 0xDC143C,
  45. 'DG': 0x32CD32,
  46. 'DI': 0x9ACD32,
  47. 'DC': 0xFFD700,
  48. 'DT': 0x4169E1,
  49. 'DU': 0x40E0D0,
  50. // peptide bases
  51. 'APN': 0xDC143C,
  52. 'GPN': 0x32CD32,
  53. 'CPN': 0xFFD700,
  54. 'TPN': 0x4169E1,
  55. })
  56. const DefaultResidueNameColor = Color(0xFF00FF)
  57. const Description = 'Assigns a color to every residue according to its name.'
  58. export const ResidueNameColorThemeParams = {}
  59. export type ResidueNameColorThemeParams = typeof ResidueNameColorThemeParams
  60. export function getResidueNameColorThemeParams(ctx: ThemeDataContext) {
  61. return ResidueNameColorThemeParams // TODO return copy
  62. }
  63. export function residueNameColor(residueName: string): Color {
  64. const c = (ResidueNameColors as { [k: string]: Color })[residueName];
  65. return c === undefined ? DefaultResidueNameColor : c
  66. }
  67. function getAtomicCompId(unit: Unit.Atomic, element: ElementIndex) {
  68. const { modifiedResidues } = unit.model.properties
  69. const compId = unit.model.atomicHierarchy.residues.auth_comp_id.value(unit.residueIndex[element])
  70. const parentId = modifiedResidues.parentId.get(compId)
  71. return parentId === undefined ? compId : parentId
  72. }
  73. function getCoarseCompId(unit: Unit.Spheres | Unit.Gaussians, element: ElementIndex) {
  74. const seqIdBegin = unit.coarseElements.seq_id_begin.value(element)
  75. const seqIdEnd = unit.coarseElements.seq_id_end.value(element)
  76. if (seqIdBegin === seqIdEnd) {
  77. const { modifiedResidues } = unit.model.properties
  78. const entityKey = unit.coarseElements.entityKey[element]
  79. const seq = unit.model.sequence.byEntityKey[entityKey]
  80. let compId = seq.compId.value(seqIdBegin - 1) // 1-indexed
  81. const parentId = modifiedResidues.parentId.get(compId)
  82. return parentId === undefined ? compId : parentId
  83. }
  84. }
  85. export function ResidueNameColorTheme(ctx: ThemeDataContext, props: PD.Values<ResidueNameColorThemeParams>): ColorTheme<ResidueNameColorThemeParams> {
  86. function color(location: Location): Color {
  87. if (StructureElement.isLocation(location)) {
  88. if (Unit.isAtomic(location.unit)) {
  89. return residueNameColor(getAtomicCompId(location.unit, location.element))
  90. } else {
  91. const compId = getCoarseCompId(location.unit, location.element)
  92. if (compId) return residueNameColor(compId)
  93. }
  94. } else if (Link.isLocation(location)) {
  95. if (Unit.isAtomic(location.aUnit)) {
  96. return residueNameColor(getAtomicCompId(location.aUnit, location.aUnit.elements[location.aIndex]))
  97. } else {
  98. const compId = getCoarseCompId(location.aUnit, location.aUnit.elements[location.aIndex])
  99. if (compId) return residueNameColor(compId)
  100. }
  101. }
  102. return DefaultResidueNameColor
  103. }
  104. return {
  105. factory: ResidueNameColorTheme,
  106. granularity: 'group',
  107. color,
  108. props,
  109. description: Description,
  110. legend: TableLegend(Object.keys(ResidueNameColors).map(name => {
  111. return [name, (ResidueNameColors as any)[name] as Color] as [string, Color]
  112. }).concat([[ 'Unknown', DefaultResidueNameColor ]]))
  113. }
  114. }
  115. export const ResidueNameColorThemeProvider: ColorTheme.Provider<ResidueNameColorThemeParams> = {
  116. label: 'Residue Name',
  117. factory: ResidueNameColorTheme,
  118. getParams: getResidueNameColorThemeParams,
  119. defaultValues: PD.getDefaultValues(ResidueNameColorThemeParams),
  120. isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
  121. }