prop.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /**
  2. * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Mandar Deshpande <mandar@ebi.ac.uk>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  7. * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  8. */
  9. import { Column, Table } from 'molstar/lib/mol-data/db';
  10. import { toTable } from 'molstar/lib/mol-io/reader/cif/schema';
  11. import { IndexedCustomProperty, Model, ResidueIndex, Unit } from 'molstar/lib/mol-model/structure';
  12. import { Structure, StructureElement } from 'molstar/lib/mol-model/structure/structure';
  13. import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition';
  14. import { MmcifFormat } from 'molstar/lib/mol-model-formats/structure/mmcif';
  15. import { PropertyWrapper } from 'molstar/lib/mol-model-props/common/wrapper';
  16. import { CustomProperty } from 'molstar/lib/mol-model-props/common/custom-property';
  17. import { CustomModelProperty } from 'molstar/lib/mol-model-props/common/custom-model-property';
  18. import { CustomPropertyDescriptor } from 'molstar/lib/mol-model/custom-property';
  19. import { arraySetAdd } from 'molstar/lib/mol-util/array';
  20. import { dateToUtcString } from 'molstar/lib/mol-util/date';
  21. export type AlphaFoldConfidence = PropertyWrapper<{
  22. score: IndexedCustomProperty.Residue<[number, string]>,
  23. category: string[]
  24. }>
  25. export namespace AlphaFoldConfidence {
  26. export function isApplicable(model?: Model): boolean {
  27. if (!model || !MmcifFormat.is(model.sourceData)) return false;
  28. return model.sourceData.data.frame.categoryNames.includes('ma_qa_metric_local');
  29. }
  30. export interface Info {
  31. timestamp_utc: string
  32. }
  33. export const Schema = {
  34. local_metric_values: {
  35. label_asym_id: Column.Schema.str,
  36. label_comp_id: Column.Schema.str,
  37. label_seq_id: Column.Schema.int,
  38. metric_id: Column.Schema.int,
  39. metric_value: Column.Schema.float,
  40. model_id: Column.Schema.int,
  41. ordinal_id: Column.Schema.int
  42. }
  43. };
  44. export type Schema = typeof Schema;
  45. function tryGetInfoFromCif(categoryName: string, model: Model): undefined | Info {
  46. if (!MmcifFormat.is(model.sourceData) || !model.sourceData.data.frame.categoryNames.includes(categoryName)) {
  47. return;
  48. }
  49. const timestampField = model.sourceData.data.frame.categories[categoryName].getField('metric_value');
  50. if (!timestampField || timestampField.rowCount === 0) return;
  51. return { timestamp_utc: timestampField.str(0) || dateToUtcString(new Date()) };
  52. }
  53. export function fromCif(ctx: CustomProperty.Context, model: Model): AlphaFoldConfidence | undefined {
  54. const info = tryGetInfoFromCif('ma_qa_metric_local', model);
  55. if (!info) return;
  56. const data = getCifData(model);
  57. const metricMap = createScoreMapFromCif(model, data.residues);
  58. return { info, data: metricMap };
  59. }
  60. export async function obtain(ctx: CustomProperty.Context, model: Model, _props: AlphaFoldConfidenceProps): Promise<CustomProperty.Data<any>> {
  61. const cif = fromCif(ctx, model);
  62. return { value: cif };
  63. }
  64. export function getConfidenceScore(e: StructureElement.Location): [number, string] {
  65. if (!Unit.isAtomic(e.unit)) return [-1, 'No Score'];
  66. const prop = AlphaFoldConfidenceProvider.get(e.unit.model).value;
  67. if (!prop || !prop.data) return [-1, 'No Score'];
  68. const rI = e.unit.residueIndex[e.element];
  69. return prop.data.score.has(rI) ? prop.data.score.get(rI)! : [-1, 'No Score'];
  70. }
  71. const _emptyArray: string[] = [];
  72. export function getCategories(structure?: Structure) {
  73. if (!structure) return _emptyArray;
  74. const prop = AlphaFoldConfidenceProvider.get(structure.models[0]).value;
  75. if (!prop || !prop.data) return _emptyArray;
  76. return prop.data.category;
  77. }
  78. function getCifData(model: Model) {
  79. if (!MmcifFormat.is(model.sourceData)) throw new Error('Data format must be mmCIF.');
  80. return {
  81. residues: toTable(Schema.local_metric_values, model.sourceData.data.frame.categories.ma_qa_metric_local),
  82. };
  83. }
  84. }
  85. export const AlphaFoldConfidenceParams = {};
  86. export type AlphaFoldConfidenceParams = typeof AlphaFoldConfidenceParams
  87. export type AlphaFoldConfidenceProps = PD.Values<AlphaFoldConfidenceParams>
  88. export const AlphaFoldConfidenceProvider: CustomModelProperty.Provider<AlphaFoldConfidenceParams, AlphaFoldConfidence> = CustomModelProperty.createProvider({
  89. label: 'AlphaFold Confidence Score',
  90. descriptor: CustomPropertyDescriptor({
  91. name: 'af_confidence_score'
  92. }),
  93. type: 'static',
  94. defaultParams: AlphaFoldConfidenceParams,
  95. getParams: () => AlphaFoldConfidenceParams,
  96. isApplicable: (data: Model) => AlphaFoldConfidence.isApplicable(data),
  97. obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<AlphaFoldConfidenceProps>) => {
  98. const p = { ...PD.getDefaultValues(AlphaFoldConfidenceParams), ...props };
  99. return await AlphaFoldConfidence.obtain(ctx, data, p);
  100. }
  101. });
  102. function createScoreMapFromCif(modelData: Model, residueData: Table<typeof AlphaFoldConfidence.Schema.local_metric_values>): AlphaFoldConfidence['data'] {
  103. const { label_asym_id, label_seq_id, metric_value, _rowCount } = residueData;
  104. const ret = new Map<ResidueIndex, [number, string]>();
  105. const categories: string[] = [];
  106. const toCategory = (v: number): 'Very low' | 'Low' | 'Confident' | 'Very high' => {
  107. if (v > 50 && v <= 70) return 'Low';
  108. if (v > 70 && v <= 90) return 'Confident';
  109. if (v > 90) return 'Very high';
  110. return 'Very low';
  111. };
  112. for (let i = 0; i < _rowCount; i++) {
  113. const confidenceScore = metric_value.value(i);
  114. const idx = modelData.atomicHierarchy.index.findResidue('1', label_asym_id.value(i), label_seq_id.value(i));
  115. const confidenceCategory = toCategory(confidenceScore);
  116. ret.set(idx, [confidenceScore, confidenceCategory]);
  117. arraySetAdd(categories, confidenceCategory);
  118. }
  119. return {
  120. score: IndexedCustomProperty.fromResidueMap(ret),
  121. category: categories
  122. };
  123. }