assembly-symmetry-cluster.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { ThemeDataContext } from '../../../mol-theme/theme';
  7. import { ColorTheme, LocationColor } from '../../../mol-theme/color';
  8. import { ParamDefinition as PD } from '../../../mol-util/param-definition'
  9. import { AssemblySymmetryProvider, AssemblySymmetry, getSymmetrySelectParam } from '../assembly-symmetry';
  10. import { Color } from '../../../mol-util/color';
  11. import { Unit, StructureElement, StructureProperties } from '../../../mol-model/structure';
  12. import { Location } from '../../../mol-model/location';
  13. import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
  14. import { getPalette, getPaletteParams } from '../../../mol-util/color/palette';
  15. import { CustomProperty } from '../../common/custom-property';
  16. const DefaultColor = Color(0xCCCCCC)
  17. function getAsymId(unit: Unit): StructureElement.Property<string> {
  18. switch (unit.kind) {
  19. case Unit.Kind.Atomic:
  20. return StructureProperties.chain.label_asym_id
  21. case Unit.Kind.Spheres:
  22. case Unit.Kind.Gaussians:
  23. return StructureProperties.coarse.asym_id
  24. }
  25. }
  26. function clusterMemberKey(asymId: string, operList: string[]) {
  27. return `${asymId}-${operList.join('|')}`
  28. }
  29. export const AssemblySymmetryClusterColorThemeParams = {
  30. ...getPaletteParams({ scaleList: 'red-yellow-blue' }),
  31. symmetryIndex: getSymmetrySelectParam(),
  32. }
  33. export type AssemblySymmetryClusterColorThemeParams = typeof AssemblySymmetryClusterColorThemeParams
  34. export function getAssemblySymmetryClusterColorThemeParams(ctx: ThemeDataContext) {
  35. const params = PD.clone(AssemblySymmetryClusterColorThemeParams)
  36. params.symmetryIndex = getSymmetrySelectParam(ctx.structure)
  37. return params
  38. }
  39. export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props: PD.Values<AssemblySymmetryClusterColorThemeParams>): ColorTheme<AssemblySymmetryClusterColorThemeParams> {
  40. let color: LocationColor = () => DefaultColor
  41. let legend: ScaleLegend | TableLegend | undefined
  42. const { symmetryIndex } = props
  43. const assemblySymmetry = ctx.structure && AssemblySymmetryProvider.get(ctx.structure)
  44. const contextHash = assemblySymmetry?.version
  45. const clusters = assemblySymmetry?.value?.[symmetryIndex]?.clusters
  46. if (clusters?.length && ctx.structure) {
  47. const clusterByMember = new Map<string, number>()
  48. for (let i = 0, il = clusters.length; i < il; ++i) {
  49. const { members } = clusters[i]!
  50. for (let j = 0, jl = members.length; j < jl; ++j) {
  51. const asymId = members[j]!.asym_id
  52. const operList = [...members[j]!.pdbx_struct_oper_list_ids || []] as string[]
  53. clusterByMember.set(clusterMemberKey(asymId, operList), i)
  54. if (operList.length === 0) {
  55. operList.push('1') // TODO hack assuming '1' is the id of the identity operator
  56. clusterByMember.set(clusterMemberKey(asymId, operList), i)
  57. }
  58. }
  59. }
  60. const palette = getPalette(clusters.length, props)
  61. legend = palette.legend
  62. color = (location: Location): Color => {
  63. if (StructureElement.Location.is(location)) {
  64. const { assembly } = location.unit.conformation.operator
  65. const asymId = getAsymId(location.unit)(location)
  66. const cluster = clusterByMember.get(clusterMemberKey(asymId, assembly.operList))
  67. return cluster !== undefined ? palette.color(cluster) : DefaultColor
  68. }
  69. return DefaultColor
  70. }
  71. }
  72. return {
  73. factory: AssemblySymmetryClusterColorTheme,
  74. granularity: 'instance',
  75. color,
  76. props,
  77. contextHash,
  78. description: 'Assigns chain colors according to assembly symmetry cluster membership calculated with BioJava and obtained via RCSB PDB.',
  79. legend
  80. }
  81. }
  82. export const AssemblySymmetryClusterColorThemeProvider: ColorTheme.Provider<AssemblySymmetryClusterColorThemeParams> = {
  83. label: 'Assembly Symmetry Cluster',
  84. category: ColorTheme.Category.Symmetry,
  85. factory: AssemblySymmetryClusterColorTheme,
  86. getParams: getAssemblySymmetryClusterColorThemeParams,
  87. defaultValues: PD.getDefaultValues(AssemblySymmetryClusterColorThemeParams),
  88. isApplicable: (ctx: ThemeDataContext) => AssemblySymmetry.isApplicable(ctx.structure),
  89. ensureCustomProperties: (ctx: CustomProperty.Context, data: ThemeDataContext) => {
  90. return data.structure ? AssemblySymmetryProvider.attach(ctx, data.structure) : Promise.resolve()
  91. }
  92. }