@datagrok/bio 2.14.2 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/css/monomer-manager.css +66 -0
  3. package/detectors.js +7 -2
  4. package/dist/111.js +1 -1
  5. package/dist/111.js.map +1 -1
  6. package/dist/234.js +1 -1
  7. package/dist/234.js.map +1 -1
  8. package/dist/242.js.map +1 -1
  9. package/dist/603.js +1 -1
  10. package/dist/603.js.map +1 -1
  11. package/dist/682.js +1 -1
  12. package/dist/682.js.map +1 -1
  13. package/dist/705.js +1 -1
  14. package/dist/705.js.map +1 -1
  15. package/dist/778.js +1 -1
  16. package/dist/778.js.map +1 -1
  17. package/dist/793.js +1 -1
  18. package/dist/793.js.map +1 -1
  19. package/dist/801.js +2 -0
  20. package/dist/801.js.map +1 -0
  21. package/dist/950.js +1 -1
  22. package/dist/950.js.map +1 -1
  23. package/dist/980.js +2 -0
  24. package/dist/980.js.map +1 -0
  25. package/dist/package-test.js +6 -6
  26. package/dist/package-test.js.map +1 -1
  27. package/dist/package.js +5 -5
  28. package/dist/package.js.map +1 -1
  29. package/files/monomer-libraries/polytool-lib.json +48 -0
  30. package/files/monomer-libraries/sample-lib-Aca-colored.json +2 -2
  31. package/package.json +20 -12
  32. package/src/analysis/sequence-space.ts +2 -1
  33. package/src/demo/bio05-helm-msa-sequence-space.ts +1 -1
  34. package/src/package-test.ts +3 -1
  35. package/src/package-types.ts +9 -1
  36. package/src/package.ts +77 -33
  37. package/src/seq_align.ts +1 -1
  38. package/src/substructure-search/substructure-search.ts +2 -2
  39. package/src/tests/WebLogo-project-tests.ts +3 -4
  40. package/src/tests/activity-cliffs-tests.ts +5 -18
  41. package/src/tests/detectors-benchmark-tests.ts +24 -9
  42. package/src/tests/mm-distance-tests.ts +4 -3
  43. package/src/tests/monomer-libraries-tests.ts +3 -3
  44. package/src/tests/seq-handler-get-helm-tests.ts +88 -0
  45. package/src/tests/sequence-space-test.ts +4 -3
  46. package/src/tests/to-atomic-level-tests.ts +2 -0
  47. package/src/tests/to-atomic-level-ui-tests.ts +74 -0
  48. package/src/utils/cell-renderer.ts +3 -0
  49. package/src/utils/convert.ts +2 -2
  50. package/src/utils/cyclized.ts +20 -1
  51. package/src/utils/dimerized.ts +12 -0
  52. package/src/utils/get-region-func-editor.ts +1 -1
  53. package/src/utils/helm-to-molfile/converter/converter.ts +58 -30
  54. package/src/utils/helm-to-molfile/converter/mol-atoms.ts +2 -0
  55. package/src/utils/helm-to-molfile/converter/mol-bonds.ts +2 -0
  56. package/src/utils/helm-to-molfile/converter/mol-wrapper.ts +5 -1
  57. package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +7 -3
  58. package/src/utils/helm-to-molfile/converter/polymer.ts +21 -6
  59. package/src/utils/helm-to-molfile/converter/types.ts +11 -0
  60. package/src/utils/helm-to-molfile/utils.ts +11 -15
  61. package/src/utils/monomer-lib/lib-manager.ts +15 -1
  62. package/src/utils/monomer-lib/library-file-manager/file-manager.ts +1 -1
  63. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +8 -0
  64. package/src/utils/monomer-lib/library-file-manager/ui.ts +150 -3
  65. package/src/utils/monomer-lib/monomer-lib.ts +59 -21
  66. package/src/utils/monomer-lib/monomer-manager/duplicate-monomer-manager.ts +155 -0
  67. package/src/utils/monomer-lib/monomer-manager/monomer-manager.ts +924 -0
  68. package/src/utils/multiple-sequence-alignment-ui.ts +3 -3
  69. package/src/utils/seq-helper/index.ts +1 -0
  70. package/src/utils/seq-helper/seq-helper.ts +131 -0
  71. package/src/utils/sequence-to-mol.ts +47 -18
  72. package/src/widgets/bio-substructure-filter.ts +9 -7
  73. package/src/widgets/package-settings-editor-widget.ts +6 -6
  74. package/src/widgets/representations.ts +12 -12
  75. package/dist/449.js +0 -2
  76. package/dist/449.js.map +0 -1
  77. /package/src/tests/{seq-handler-get-region.ts → seq-handler-get-region-tests.ts} +0 -0
@@ -70,14 +70,14 @@ export async function multipleSequenceAlignmentUI(
70
70
 
71
71
  let prevSeqCol = seqCol;
72
72
  const colInput = ui.input.column(
73
- 'Sequence', {table: table, value: seqCol, onValueChanged: async (input: DG.InputBase<DG.Column<string>>): Promise<void> => {
74
- if (!input.value || input.value.semType !== DG.SEMTYPE.MACROMOLECULE) {
73
+ 'Sequence', {table: table, value: seqCol, onValueChanged: async (value: DG.Column<any>) => {
74
+ if (!value || value.semType !== DG.SEMTYPE.MACROMOLECULE) {
75
75
  okBtn.disabled = true;
76
76
  await delay(0); // to
77
77
  colInput.value = prevSeqCol as DG.Column<string>;
78
78
  return;
79
79
  }
80
- prevSeqCol = input.value;
80
+ prevSeqCol = value;
81
81
  okBtn.disabled = false;
82
82
  performAlignment = await onColInputChange(
83
83
  colInput.value, table, pepseaInputRootStyles, kalignInputRootStyles,
@@ -0,0 +1 @@
1
+ export {SeqHelper} from './seq-helper';
@@ -0,0 +1,131 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import wu from 'wu';
6
+
7
+ import {ISeqHelper, ISubstruct, SUBSTRUCT_COL, ToAtomicLevelResType} from '@datagrok-libraries/bio/src/utils/seq-helper';
8
+ import {RDModule, RDMol} from '@datagrok-libraries/chem-meta/src/rdkit-api';
9
+ import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
10
+ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
11
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
12
+
13
+ import {HelmToMolfileConverter} from '../helm-to-molfile/converter';
14
+ import {Column, DataFrame} from 'datagrok-api/dg';
15
+ import {MolfileWithMap, MonomerMap} from '../helm-to-molfile/converter/types';
16
+
17
+ import {_package, getMonomerLibHelper} from '../../package';
18
+ import {MonomerLibManager} from '../monomer-lib/lib-manager';
19
+
20
+ type SeqHelperWindowType = Window & { $seqHelperPromise?: Promise<SeqHelper> };
21
+ declare const window: SeqHelperWindowType;
22
+
23
+ export class SeqHelper implements ISeqHelper {
24
+ constructor(
25
+ private readonly libHelper: IMonomerLibHelper,
26
+ private readonly helmHelper: IHelmHelper,
27
+ private readonly rdKitModule: RDModule
28
+ ) {}
29
+
30
+ getHelmToMolfileConverter(df: DataFrame, helmCol: Column<string>) {
31
+ return new HelmToMolfileConverter(helmCol, df, this.libHelper, this.helmHelper);
32
+ }
33
+
34
+ async helmToAtomicLevel(
35
+ helmCol: DG.Column<string>, chiralityEngine?: boolean, highlight?: boolean
36
+ ): Promise<ToAtomicLevelResType> {
37
+ const getUnusedName = (df: DG.DataFrame | undefined, colName: string): string => {
38
+ if (!df) return colName;
39
+ return df.columns.getUnusedName(colName);
40
+ };
41
+
42
+ const df: DG.DataFrame = helmCol.dataFrame;
43
+ const molColName: string = getUnusedName(df, `molfile(${helmCol})`);
44
+ const molHlColName: string = getUnusedName(df, `~${molColName}-hl`);
45
+
46
+ const converter = this.getHelmToMolfileConverter(df, helmCol);
47
+
48
+ //#region From HelmToMolfileConverter.convertToRdKitBeautifiedMolfileColumn
49
+
50
+ const molfilesV3K = converter.convertToMolfileV3K(this.rdKitModule);
51
+
52
+ const beautifiedMolList: (RDMol | null)[] = molfilesV3K.map((item) => {
53
+ const molfile = item.molfile;
54
+ if (molfile === '')
55
+ return null;
56
+ const mol = this.rdKitModule.get_mol(molfile);
57
+ if (!mol)
58
+ return null;
59
+ mol.set_new_coords();
60
+ mol.normalize_depiction(1);
61
+ mol.straighten_depiction(true);
62
+ return mol;
63
+ });
64
+
65
+ let molList: string[];
66
+ if (chiralityEngine) {
67
+ molList = converter.getMolV3000ViaOCL(beautifiedMolList, molColName).toList();
68
+ // TODO: Cleanup mol objects
69
+ } else {
70
+ molList = beautifiedMolList.map((mol) => {
71
+ if (mol === null)
72
+ return '';
73
+ const molBlock = mol.get_v3Kmolblock();
74
+ mol!.delete();
75
+ return molBlock;
76
+ });
77
+ }
78
+
79
+ //#endregion From HelmToMolfileConverter
80
+
81
+ const molHlList = molfilesV3K.map((item: MolfileWithMap) => {
82
+ const mmList: MonomerMap[] = item.monomers;
83
+
84
+ const hlAtoms: { [key: number]: number[] } = {};
85
+ const hlBonds: { [key: number]: number[] } = {};
86
+
87
+ for (const [mm, mmI] of wu.enumerate(mmList)) {
88
+ if (mmI >= 2) continue;
89
+
90
+ const mmColor = [Math.random(), Math.random(), Math.random(), 0.3]; // green color
91
+ for (const mAtom of mm.atoms) {
92
+ hlAtoms[mAtom] = mmColor;
93
+ }
94
+ for (const mBond of mm.bonds) {
95
+ hlBonds[mBond] = mmColor;
96
+ }
97
+ }
98
+
99
+ let resSubstruct: ISubstruct = {
100
+ atoms: Object.keys(hlAtoms).map((k) => parseInt(k)),
101
+ bonds: Object.keys(hlBonds).map((k) => parseInt(k)),
102
+ highlightAtomColors: hlAtoms,
103
+ highlightBondColors: hlBonds,
104
+ };
105
+
106
+ return resSubstruct;
107
+ });
108
+
109
+ const molCol = DG.Column.fromStrings(molColName, molList);
110
+ molCol.semType = 'Molecule';
111
+ molCol.temp[SUBSTRUCT_COL] = molHlColName;
112
+ const molHlCol = DG.Column.fromList(DG.COLUMN_TYPE.OBJECT, molHlColName, molHlList);
113
+ molHlCol.semType = 'Molecule-substruct';
114
+
115
+ return {molCol: molCol, molHighlightCol: molHlCol};
116
+ }
117
+
118
+ static getInstance(): Promise<SeqHelper> {
119
+ let res = window.$seqHelperPromise;
120
+ if (res == undefined) {
121
+ res = window.$seqHelperPromise = (async () => {
122
+ if (!_package.initialized)
123
+ throw new Error('Bio package is not initialized, call Bio:getSeqHelper');
124
+ const instance = new SeqHelper(
125
+ await MonomerLibManager.getInstance(), await getHelmHelper(), _package.rdKitModule);
126
+ return instance;
127
+ })();
128
+ }
129
+ return res;
130
+ }
131
+ }
@@ -1,4 +1,3 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
1
  import * as grok from 'datagrok-api/grok';
3
2
  import * as ui from 'datagrok-api/ui';
4
3
  import * as DG from 'datagrok-api/dg';
@@ -7,31 +6,61 @@ import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomi
7
6
  import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
8
7
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
9
8
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
10
+ import {getSeqHelper, ToAtomicLevelResType} from '@datagrok-libraries/bio/src/utils/seq-helper';
11
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
10
12
 
11
- import {helm2mol} from './helm-to-molfile/utils';
12
13
  import {checkInputColumnUI} from './check-input-column';
13
14
 
14
15
  export async function sequenceToMolfile(
15
16
  df: DG.DataFrame, macroMolecule: DG.Column, nonlinear: boolean, monomerLib: IMonomerLib
16
- ): Promise<void> {
17
- if (DG.Func.find({package: 'Chem', name: 'getRdKitModule'}).length === 0) {
17
+ ): Promise<DG.Column<string> | null> {
18
+ let rdKitModule: RDModule;
19
+ try {
20
+ rdKitModule = await getRdKitModule();
21
+ } catch (ex: any) {
18
22
  grok.shell.warning('Transformation to atomic level requires package "Chem" installed.');
19
- return;
23
+ return null;
20
24
  }
25
+
26
+ let resCol: DG.Column<string> | null = null;
21
27
  if (nonlinear) {
28
+ const seqHelper = await getSeqHelper();
22
29
  const seqSh = SeqHandler.forColumn(macroMolecule);
23
- if (!seqSh.isHelm())
24
- macroMolecule = seqSh.convert(NOTATION.HELM);
25
- return helm2mol(df, macroMolecule);
26
- }
27
- if (!checkInputColumnUI(macroMolecule, 'To Atomic Level'))
28
- return;
29
- const atomicLevelRes = await _toAtomicLevel(df, macroMolecule, monomerLib);
30
- if (atomicLevelRes.col !== null) {
31
- df.columns.add(atomicLevelRes.col, true);
32
- await grok.data.detectSemanticTypes(df);
33
- }
34
30
 
35
- if (atomicLevelRes.warnings && atomicLevelRes.warnings.length > 0)
36
- grok.shell.warning(ui.list(atomicLevelRes.warnings));
31
+ let atomicLevelRes: ToAtomicLevelResType;
32
+
33
+ let helmCol: DG.Column<string>;
34
+ let seqColName!: string;
35
+ if (seqSh.isHelm())
36
+ helmCol = macroMolecule;
37
+ else {
38
+ seqColName = macroMolecule.name;
39
+ macroMolecule.name = `__${seqColName}`;
40
+ helmCol = seqSh.convert(NOTATION.HELM);
41
+ helmCol.name = seqColName;
42
+ df.columns.add(helmCol, false);
43
+ }
44
+ try {
45
+ atomicLevelRes = await seqHelper.helmToAtomicLevel(helmCol, true, true);
46
+ } finally {
47
+ if (helmCol !== macroMolecule) {
48
+ df.columns.remove(helmCol.name);
49
+ macroMolecule.name = seqColName;
50
+ }
51
+ }
52
+ df.columns.add(atomicLevelRes.molCol);
53
+ df.columns.add(atomicLevelRes.molHighlightCol);
54
+ resCol = atomicLevelRes.molCol;
55
+ } else {
56
+ if (!checkInputColumnUI(macroMolecule, 'To Atomic Level'))
57
+ return null;
58
+ const atomicLevelRes = await _toAtomicLevel(df, macroMolecule, monomerLib);
59
+ if (atomicLevelRes.col !== null) {
60
+ df.columns.add(atomicLevelRes.col, true);
61
+ resCol = atomicLevelRes.col;
62
+ }
63
+ }
64
+ if (resCol) await grok.data.detectSemanticTypes(df);
65
+ return resCol;
37
66
  }
@@ -296,9 +296,11 @@ export class FastaBioFilter extends BioFilterBase<BioFilterProps> {
296
296
  super();
297
297
 
298
298
  this.substructureInput = ui.input.string('', {
299
- value: '', onValueChanged: () => {
300
- this.props = new BioFilterProps(this.substructureInput.value);
301
- if (!this._propsChanging) this.onChanged.next();
299
+ value: '', onValueChanged: (value) => {
300
+ window.setTimeout(() => {
301
+ this.props = new BioFilterProps(value);
302
+ if (!this._propsChanging) this.onChanged.next();
303
+ }, 0 /* next event cycle */);
302
304
  }, placeholder: 'Substructure'
303
305
  });
304
306
  }
@@ -338,14 +340,14 @@ export class SeparatorBioFilter extends BioFilterBase<SeparatorFilterProps> {
338
340
  super();
339
341
 
340
342
  this.substructureInput = ui.input.string('', {
341
- value: '', onValueChanged: () => {
342
- this.props = new SeparatorFilterProps(this.substructureInput.value, this.props.separator);
343
+ value: '', onValueChanged: (value) => {
344
+ this.props = new SeparatorFilterProps(value, this.props.separator);
343
345
  if (!this._propsChanging) this.onChanged.next();
344
346
  }, placeholder: 'Substructure'
345
347
  });
346
348
  this.separatorInput = ui.input.string('', {
347
- value: this.colSeparator = colSeparator, onValueChanged: () => {
348
- const separator: string | undefined = !!this.separatorInput.value ? this.separatorInput.value : undefined;
349
+ value: this.colSeparator = colSeparator, onValueChanged: (value) => {
350
+ const separator: string | undefined = !!value ? value : undefined;
349
351
  this.props = new SeparatorFilterProps(this.props.substructure, separator);
350
352
  if (!this._propsChanging) this.onChanged.next();
351
353
  }, placeholder: 'Separator'
@@ -24,9 +24,9 @@ export class PackageSettingsEditorWidget extends DG.Widget {
24
24
  const maxMonomerLengthInput = ui.input.int('Max Monomer Length', {
25
25
  value: _package.properties.maxMonomerLength!,
26
26
  nullable: true, min: 0,
27
- onValueChanged: () => {
27
+ onValueChanged: (value) => {
28
28
  // Handle user changed value
29
- _package.properties.maxMonomerLength = maxMonomerLengthInput.value ?? null;
29
+ _package.properties.maxMonomerLength = value ?? null;
30
30
  },
31
31
  tooltipText: this.maxMonomerLengthProp.description,
32
32
  });
@@ -34,8 +34,8 @@ export class PackageSettingsEditorWidget extends DG.Widget {
34
34
  const tooltipWebLogoInput = ui.input.bool('Tooltip WebLogo', {
35
35
  value: _package.properties.tooltipWebLogo,
36
36
  nullable: false,
37
- onValueChanged: () => {
38
- _package.properties.tooltipWebLogo = tooltipWebLogoInput.value!;
37
+ onValueChanged: (value) => {
38
+ _package.properties.tooltipWebLogo = value;
39
39
  },
40
40
  tooltipText: this.tooltipWebLogo.description,
41
41
  });
@@ -43,8 +43,8 @@ export class PackageSettingsEditorWidget extends DG.Widget {
43
43
  const defaultSeparatorInput = ui.input.choice('Default Separator', {
44
44
  value: _package.properties.defaultSeparator,
45
45
  items: ['.', '/', '-'],
46
- onValueChanged: () => {
47
- _package.properties.defaultSeparator = defaultSeparatorInput.value!;
46
+ onValueChanged: (value) => {
47
+ _package.properties.defaultSeparator = value;
48
48
  },
49
49
  tooltipText: this.defaultSeparator.description,
50
50
  });
@@ -37,12 +37,12 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
37
37
  const maxMonomerLengthInput = ui.input.int('Max Monomer Length', {
38
38
  value: maxMonomerLength!,
39
39
  nullable: true, min: 1, max: 50, step: 1,
40
- onValueChanged: () => {
41
- if (maxMonomerLengthInput.value == 0)
40
+ onValueChanged: (value) => {
41
+ if (value == 0)
42
42
  setTimeout(() => { maxMonomerLengthInput.value = null!; }, 0);
43
43
  else {
44
- const value = maxMonomerLengthInput.value ?? '';
45
- const tagValue = value == null ? '' : value.toString();
44
+ const newValue = value ?? '';
45
+ const tagValue = newValue == null ? '' : newValue.toString();
46
46
  col.temp[Temps.maxMonomerLength] = tagValue;
47
47
  col.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.true;
48
48
  col.dataFrame.fireValuesChanged();
@@ -53,8 +53,8 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
53
53
 
54
54
  const gapLengthInput = ui.input.int('Monomer Margin', {
55
55
  value: col.temp[mmcrTemps.gapLength] ?? 0,
56
- onValueChanged: () => {
57
- col.temp[mmcrTemps.gapLength] = gapLengthInput.value;
56
+ onValueChanged: (value) => {
57
+ col.temp[mmcrTemps.gapLength] = value;
58
58
  col.temp[mmcrTemps.rendererSettingsChanged] = rendererSettingsChangedState.true;
59
59
  col.dataFrame.fireValuesChanged();
60
60
  },
@@ -63,8 +63,8 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
63
63
 
64
64
  const colorCodeInput = ui.input.bool('Color Code', {
65
65
  value: (col?.temp['color-code'] != null) ? col.temp['color-code'] : true,
66
- onValueChanged: () => {
67
- col.temp['color-code'] = colorCodeInput.value;
66
+ onValueChanged: (value) => {
67
+ col.temp['color-code'] = value;
68
68
  col.dataFrame.fireValuesChanged();
69
69
  },
70
70
  tooltipText: 'Color code'
@@ -73,8 +73,8 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
73
73
  const referenceSequenceInput = ui.input.string('Reference Sequence', {
74
74
  value: (col?.temp['reference-sequence'] != null) ? col?.temp['reference-sequence'] : '',
75
75
  nullable: true,
76
- onValueChanged: () => {
77
- col.temp['reference-sequence'] = referenceSequenceInput.value;
76
+ onValueChanged: (value) => {
77
+ col.temp['reference-sequence'] = value;
78
78
  col.dataFrame.fireValuesChanged();
79
79
  },
80
80
  tooltipText: 'Reference sequence is not empty, then the sequence will be render ' + '\n' +
@@ -83,8 +83,8 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
83
83
 
84
84
  const compareWithCurrentInput = ui.input.bool('Compare with current', {
85
85
  value: (col?.temp['compare-with-current'] != null) ? col.temp['compare-with-current'] : true,
86
- onValueChanged: () => {
87
- col.temp['compare-with-current'] = compareWithCurrentInput.value;
86
+ onValueChanged: (value) => {
87
+ col.temp['compare-with-current'] = value;
88
88
  col.dataFrame.fireValuesChanged();
89
89
  },
90
90
  tooltipText: 'When on, all sequences get rendered in the "diff" mode'