geometry-quality.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * Copyright (c) 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 { Color } from '../../../mol-util/color';
  10. import { StructureElement } from '../../../mol-model/structure';
  11. import { Location } from '../../../mol-model/location';
  12. import { CustomProperty } from '../../common/custom-property';
  13. import { ValidationReportProvider, ValidationReport } from '../validation-report';
  14. import { TableLegend } from '../../../mol-util/legend';
  15. import { PolymerType } from '../../../mol-model/structure/model/types';
  16. import { SetUtils } from '../../../mol-util/set';
  17. const DefaultColor = Color(0x909090)
  18. const NoIssuesColor = Color(0x2166ac)
  19. const OneIssueColor = Color(0xfee08b)
  20. const TwoIssuesColor = Color(0xf46d43)
  21. const ThreeOrMoreIssuesColor = Color(0xa50026)
  22. const ColorLegend = TableLegend([
  23. ['Data unavailable', DefaultColor],
  24. ['No issues', NoIssuesColor],
  25. ['One issue', OneIssueColor],
  26. ['Two issues', TwoIssuesColor],
  27. ['Three or more issues', ThreeOrMoreIssuesColor],
  28. ])
  29. export function getGeometricQualityColorThemeParams(ctx: ThemeDataContext) {
  30. const validationReport = ctx.structure && ValidationReportProvider.get(ctx.structure.models[0]).value
  31. const options: [string, string][] = []
  32. if (validationReport) {
  33. const kinds = new Set<string>()
  34. validationReport.geometryIssues.forEach(v => v.forEach(k => kinds.add(k)))
  35. kinds.forEach(k => options.push([k, k]))
  36. }
  37. return {
  38. ignore: PD.MultiSelect([] as string[], options)
  39. }
  40. }
  41. export type GeometricQualityColorThemeParams = ReturnType<typeof getGeometricQualityColorThemeParams>
  42. export function GeometryQualityColorTheme(ctx: ThemeDataContext, props: PD.Values<GeometricQualityColorThemeParams>): ColorTheme<GeometricQualityColorThemeParams> {
  43. let color: LocationColor = () => DefaultColor
  44. const validationReport = ctx.structure && ValidationReportProvider.get(ctx.structure.models[0])
  45. const contextHash = validationReport?.version
  46. const value = validationReport?.value
  47. const model = ctx.structure?.models[0]
  48. if (value && model) {
  49. const { geometryIssues, clashes, bondOutliers, angleOutliers } = value
  50. const residueIndex = model.atomicHierarchy.residueAtomSegments.index
  51. const { polymerType } = model.atomicHierarchy.derived.residue
  52. const ignore = new Set(props.ignore)
  53. color = (location: Location): Color => {
  54. if (StructureElement.Location.is(location) && location.unit.model === model) {
  55. const { element } = location
  56. const rI = residueIndex[element]
  57. const value = geometryIssues.get(rI)
  58. if (value === undefined) return DefaultColor
  59. let count = SetUtils.differenceSize(value, ignore)
  60. if (count > 0 && polymerType[rI] === PolymerType.NA) {
  61. count = 0
  62. if (!ignore.has('clash') && clashes.getVertexEdgeCount(element) > 0) count += 1
  63. if (!ignore.has('mog-bond-outlier') && bondOutliers.index.has(element)) count += 1
  64. if (!ignore.has('mog-angle-outlier') && angleOutliers.index.has(element)) count += 1
  65. }
  66. switch (count) {
  67. case undefined: return DefaultColor
  68. case 0: return NoIssuesColor
  69. case 1: return OneIssueColor
  70. case 2: return TwoIssuesColor
  71. default: return ThreeOrMoreIssuesColor
  72. }
  73. }
  74. return DefaultColor
  75. }
  76. }
  77. return {
  78. factory: GeometryQualityColorTheme,
  79. granularity: 'group',
  80. color,
  81. props,
  82. contextHash,
  83. description: 'Assigns residue colors according to the number of (filtered) geometry issues. Data from wwPDB Validation Report, obtained via RCSB PDB.',
  84. legend: ColorLegend
  85. }
  86. }
  87. export const GeometryQualityColorThemeProvider: ColorTheme.Provider<GeometricQualityColorThemeParams> = {
  88. label: 'Geometry Quality',
  89. category: ColorTheme.Category.Validation,
  90. factory: GeometryQualityColorTheme,
  91. getParams: getGeometricQualityColorThemeParams,
  92. defaultValues: PD.getDefaultValues(getGeometricQualityColorThemeParams({})),
  93. isApplicable: (ctx: ThemeDataContext) => ValidationReport.isApplicable(ctx.structure?.models[0]),
  94. ensureCustomProperties: {
  95. attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => data.structure ? ValidationReportProvider.attach(ctx, data.structure.models[0], void 0, true) : Promise.resolve(),
  96. detach: (_, data) => data.structure && data.structure.models[0].customProperties.reference(ValidationReportProvider.descriptor, false)
  97. }
  98. }