@datagrok/bio 2.15.13 → 2.16.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 (78) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/detectors.js +16 -11
  3. package/dist/455.js.map +1 -1
  4. package/dist/980.js +1 -1
  5. package/dist/980.js.map +1 -1
  6. package/dist/package-test.js +6 -6
  7. package/dist/package-test.js.map +1 -1
  8. package/dist/package.js +3 -3
  9. package/dist/package.js.map +1 -1
  10. package/package.json +5 -5
  11. package/src/analysis/sequence-activity-cliffs.ts +3 -4
  12. package/src/analysis/sequence-diversity-viewer.ts +5 -3
  13. package/src/analysis/sequence-similarity-viewer.ts +8 -5
  14. package/src/analysis/sequence-space.ts +3 -2
  15. package/src/calculations/monomerLevelMols.ts +3 -3
  16. package/src/demo/bio01-similarity-diversity.ts +4 -1
  17. package/src/package-test.ts +1 -1
  18. package/src/package-types.ts +35 -2
  19. package/src/package.ts +57 -71
  20. package/src/tests/WebLogo-layout-tests.ts +1 -1
  21. package/src/tests/WebLogo-positions-test.ts +11 -5
  22. package/src/tests/WebLogo-project-tests.ts +1 -1
  23. package/src/tests/activity-cliffs-utils.ts +11 -14
  24. package/src/tests/bio-tests.ts +85 -79
  25. package/src/tests/checkInputColumn-tests.ts +15 -10
  26. package/src/tests/converters-test.ts +12 -5
  27. package/src/tests/detectors-benchmark-tests.ts +5 -2
  28. package/src/tests/detectors-tests.ts +51 -44
  29. package/src/tests/detectors-weak-and-likely-tests.ts +12 -5
  30. package/src/tests/fasta-export-tests.ts +13 -5
  31. package/src/tests/helm-tests.ts +85 -0
  32. package/src/tests/mm-distance-tests.ts +14 -7
  33. package/src/tests/monomer-libraries-tests.ts +1 -1
  34. package/src/tests/msa-tests.ts +33 -24
  35. package/src/tests/renderers-monomer-placer-tests.ts +2 -5
  36. package/src/tests/renderers-test.ts +15 -9
  37. package/src/tests/scoring.ts +9 -6
  38. package/src/tests/seq-handler-get-helm-tests.ts +7 -5
  39. package/src/tests/seq-handler-get-region-tests.ts +9 -3
  40. package/src/tests/seq-handler-splitted-tests.ts +11 -5
  41. package/src/tests/seq-handler-tests.ts +17 -10
  42. package/src/tests/sequence-space-utils.ts +9 -4
  43. package/src/tests/splitters-test.ts +5 -4
  44. package/src/tests/substructure-filters-tests.ts +16 -13
  45. package/src/tests/to-atomic-level-tests.ts +5 -3
  46. package/src/tests/to-atomic-level-ui-tests.ts +4 -1
  47. package/src/tests/utils/detectors-utils.ts +4 -4
  48. package/src/utils/calculate-scores.ts +11 -9
  49. package/src/utils/cell-renderer-custom.ts +27 -17
  50. package/src/utils/cell-renderer.ts +14 -8
  51. package/src/utils/check-input-column.ts +13 -9
  52. package/src/utils/context-menu.ts +4 -4
  53. package/src/utils/convert.ts +21 -14
  54. package/src/utils/get-region-func-editor.ts +8 -5
  55. package/src/utils/get-region.ts +4 -5
  56. package/src/utils/helm-to-molfile/converter/helm.ts +4 -4
  57. package/src/utils/helm-to-molfile/utils.ts +5 -6
  58. package/src/utils/macromolecule-column-widget.ts +6 -7
  59. package/src/utils/monomer-cell-renderer-base.ts +8 -1
  60. package/src/utils/monomer-lib/lib-manager.ts +3 -2
  61. package/src/utils/monomer-lib/monomer-colors.ts +10 -10
  62. package/src/utils/monomer-lib/monomer-lib-base.ts +6 -1
  63. package/src/utils/monomer-lib/monomer-lib.ts +15 -9
  64. package/src/utils/multiple-sequence-alignment-ui.ts +30 -30
  65. package/src/utils/save-as-fasta.ts +19 -12
  66. package/src/utils/seq-helper/seq-handler.ts +859 -0
  67. package/src/utils/seq-helper/seq-helper.ts +11 -21
  68. package/src/utils/sequence-to-mol.ts +7 -8
  69. package/src/utils/split-to-monomers.ts +7 -2
  70. package/src/utils/types.ts +8 -7
  71. package/src/utils/ui-utils.ts +2 -2
  72. package/src/viewers/web-logo-viewer.ts +18 -16
  73. package/src/widgets/bio-substructure-filter.ts +1 -2
  74. package/src/widgets/composition-analysis-widget.ts +6 -6
  75. package/src/widgets/representations.ts +7 -4
  76. package/src/tests/detectors-custom-notation-tests.ts +0 -37
  77. package/src/utils/cyclized.ts +0 -89
  78. package/src/utils/dimerized.ts +0 -10
@@ -39,10 +39,10 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
39
39
 
40
40
  constructor(
41
41
  monomers: MonomerLibDataType,
42
- public readonly source: string | undefined = undefined,
42
+ source: string,
43
43
  public readonly error: string | undefined = undefined,
44
44
  ) {
45
- super(monomers);
45
+ super(monomers, source);
46
46
  for (const [_monomerType, monomersOfType] of Object.entries(this._monomers)) {
47
47
  for (const [_monomerSymbol, monomer] of Object.entries(monomersOfType))
48
48
  monomer.lib = this;
@@ -112,10 +112,6 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
112
112
  return res;
113
113
  }
114
114
 
115
- getMonomerSymbolsByType(polymerType: PolymerType): string[] {
116
- return Object.keys(this._monomers[polymerType]);
117
- }
118
-
119
115
  /** Get a list of monomers with specified element attached to specified
120
116
  * R-group
121
117
  * WARNING: RGroup numbering starts from 1, not 0*/
@@ -241,21 +237,31 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
241
237
  return resStr;
242
238
  }
243
239
 
244
- override(data: MonomerLibData): IMonomerLibBase {
245
- return new OverriddenMonomerLib(data, this);
240
+ override(data: MonomerLibData, source: string): IMonomerLibBase {
241
+ return new OverriddenMonomerLib(data, source, this);
246
242
  }
247
243
  }
248
244
 
249
245
  class OverriddenMonomerLib extends MonomerLibBase {
250
246
  constructor(
251
247
  private readonly data: MonomerLibData,
248
+ source: string,
252
249
  private readonly base: MonomerLibBase
253
250
  ) {
254
- super(data);
251
+ super(data, source);
255
252
  }
256
253
 
257
254
  get onChanged(): Observable<any> { return this.base.onChanged; }
258
255
 
256
+ override getMonomerSymbolsByType(polymerType: PolymerType): string[] {
257
+ const resList = this.base.getMonomerSymbolsByType(polymerType);
258
+ for (const overrideSymbol of Object.keys(this.data[polymerType] ?? {})) {
259
+ if (!resList.includes(overrideSymbol))
260
+ resList.push(overrideSymbol);
261
+ }
262
+ return resList;
263
+ }
264
+
259
265
  addMissingMonomer(polymerType: PolymerType, monomerSymbol: string): Monomer {
260
266
  return this.base.addMissingMonomer(polymerType, monomerSymbol);
261
267
  }
@@ -5,21 +5,20 @@ import * as ui from 'datagrok-api/ui';
5
5
  import {ColumnInputOptions} from '@datagrok-libraries/utils/src/type-declarations';
6
6
  import {delay} from '@datagrok-libraries/utils/src/test';
7
7
  import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
- import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
8
+ import {ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
9
9
 
10
10
  import {MsaWarning, runKalign} from './multiple-sequence-alignment';
11
11
  import {pepseaMethods, runPepsea} from './pepsea';
12
- import {checkInputColumnUI} from './check-input-column';
13
- import {multipleSequenceAlginmentUIOptions} from './types';
12
+ import {checkInputColumn} from './check-input-column';
13
+ import {MultipleSequenceAlignmentUIOptions} from './types';
14
14
  import {kalignVersion, msaDefaultOptions} from './constants';
15
15
  import {awaitContainerStart} from './docker';
16
16
 
17
- import {_package} from '../package';
18
-
19
17
  import '../../css/msa.css';
18
+ import {_package} from '../package';
20
19
 
21
20
  export async function multipleSequenceAlignmentUI(
22
- options: multipleSequenceAlginmentUIOptions = {},
21
+ options: MultipleSequenceAlignmentUIOptions, seqHelper: ISeqHelper,
23
22
  ): Promise<DG.Column> {
24
23
  return new Promise(async (resolve, reject) => {
25
24
  options.clustersCol ??= null;
@@ -70,20 +69,22 @@ export async function multipleSequenceAlignmentUI(
70
69
 
71
70
  let prevSeqCol = seqCol;
72
71
  const colInput = ui.input.column(
73
- 'Sequence', {table: table, value: seqCol, onValueChanged: async (value: DG.Column<any>) => {
74
- if (!value || value.semType !== DG.SEMTYPE.MACROMOLECULE) {
75
- okBtn.disabled = true;
76
- await delay(0); // to
77
- colInput.value = prevSeqCol as DG.Column<string>;
78
- return;
79
- }
80
- prevSeqCol = value;
81
- okBtn.disabled = false;
82
- performAlignment = await onColInputChange(
83
- colInput.value, table, pepseaInputRootStyles, kalignInputRootStyles,
84
- methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
85
- );
86
- }, filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE} as ColumnInputOptions
72
+ 'Sequence', {
73
+ table: table, value: seqCol, onValueChanged: async (value: DG.Column<any>) => {
74
+ if (!value || value.semType !== DG.SEMTYPE.MACROMOLECULE) {
75
+ okBtn.disabled = true;
76
+ await delay(0); // to
77
+ colInput.value = prevSeqCol as DG.Column<string>;
78
+ return;
79
+ }
80
+ prevSeqCol = value;
81
+ okBtn.disabled = false;
82
+ performAlignment = await onColInputChange(
83
+ colInput.value, table, seqHelper, pepseaInputRootStyles, kalignInputRootStyles,
84
+ methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
85
+ );
86
+ }, filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE
87
+ } as ColumnInputOptions
87
88
  ) as DG.InputBase<DG.Column<string>>;
88
89
  colInput.setTooltip('Sequences column to use for alignment');
89
90
  const clustersColInput = ui.input.column('Clusters', {table: table, value: options.clustersCol!});
@@ -103,7 +104,7 @@ export async function multipleSequenceAlignmentUI(
103
104
  //if column is specified (from tests), run alignment and resolve with the result
104
105
  if (options.col) {
105
106
  performAlignment = await onColInputChange(
106
- options.col, table, pepseaInputRootStyles, kalignInputRootStyles,
107
+ options.col, table, seqHelper, pepseaInputRootStyles, kalignInputRootStyles,
107
108
  methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
108
109
  );
109
110
  await onDialogOk(colInput, table, performAlignment, resolve, reject);
@@ -146,7 +147,7 @@ async function onDialogOk(
146
147
 
147
148
 
148
149
  async function onColInputChange(
149
- col: DG.Column<string>, table: DG.DataFrame,
150
+ col: DG.Column<string>, table: DG.DataFrame, seqHelper: ISeqHelper,
150
151
  pepseaInputRootStyles: CSSStyleDeclaration[], kalignInputRootStyles: CSSStyleDeclaration[],
151
152
  methodInput: DG.InputBase<string | null>, clustersColInput: DG.InputBase<DG.Column<any> | null>,
152
153
  gapOpenInput: DG.InputBase<number | null>, gapExtendInput: DG.InputBase<number | null>,
@@ -157,20 +158,19 @@ async function onColInputChange(
157
158
  return;
158
159
  const unusedName = table.columns.getUnusedName(`msa(${col.name})`);
159
160
 
160
- if (checkInputColumnUI(col, col.name,
161
- [NOTATION.FASTA, NOTATION.SEPARATOR], [ALPHABET.DNA, ALPHABET.RNA, ALPHABET.PT], false)
161
+ if (checkInputColumn(col, col.name, seqHelper,
162
+ [NOTATION.FASTA, NOTATION.SEPARATOR], [ALPHABET.DNA, ALPHABET.RNA, ALPHABET.PT])[0]
162
163
  ) { // Kalign - natural alphabets. if the notation is separator, convert to fasta and then run kalign
163
164
  switchDialog(pepseaInputRootStyles, kalignInputRootStyles, 'kalign');
164
165
  gapOpenInput.value = null;
165
166
  gapExtendInput.value = null;
166
167
  terminalGapInput.value = null;
167
- const potentialColSh = SeqHandler.forColumn(col);
168
+ const potentialColSh = seqHelper.getSeqHandler(col);
168
169
  const performCol: DG.Column<string> = potentialColSh.isFasta() ? col :
169
170
  potentialColSh.convert(NOTATION.FASTA);
170
171
  return async () => await runKalign(performCol, false, unusedName, clustersColInput.value);
171
- } else if (checkInputColumnUI(col, col.name,
172
- [NOTATION.HELM], [], false)
173
- ) { // PepSeA branch - Helm notation or separator notation with unknown alphabets
172
+ } else if (checkInputColumn(col, col.name, seqHelper, [NOTATION.HELM], [])[0]) {
173
+ // PepSeA branch - Helm notation or separator notation with unknown alphabets
174
174
  switchDialog(pepseaInputRootStyles, kalignInputRootStyles, 'pepsea');
175
175
  gapOpenInput.value ??= msaDefaultOptions.pepsea.gapOpen;
176
176
  gapExtendInput.value ??= msaDefaultOptions.pepsea.gapExtend;
@@ -180,9 +180,9 @@ async function onColInputChange(
180
180
  return runPepsea(col, unusedName, methodInput.value!,
181
181
  gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
182
182
  };
183
- } else if (checkInputColumnUI(col, col.name, [NOTATION.SEPARATOR], [ALPHABET.UN], false)) {
183
+ } else if (checkInputColumn(col, col.name, seqHelper, [NOTATION.SEPARATOR], [ALPHABET.UN])[0]) {
184
184
  //if the column is separator with unknown alphabet, it might be helm. check if it can be converted to helm
185
- const potentialColSh = SeqHandler.forColumn(col);
185
+ const potentialColSh = seqHelper.getSeqHandler(col);
186
186
  const helmCol = potentialColSh.convert(NOTATION.HELM);
187
187
  switchDialog(pepseaInputRootStyles, kalignInputRootStyles, 'pepsea');
188
188
  gapOpenInput.value ??= msaDefaultOptions.pepsea.gapOpen;
@@ -3,13 +3,16 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as grok from 'datagrok-api/grok';
4
4
 
5
5
  import wu from 'wu';
6
- import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
6
+
7
7
  import {ISeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
8
+ import {ISeqHandler} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
9
+
10
+ import {_package} from '../package';
8
11
 
9
12
  const FASTA_LINE_WIDTH = 60;
10
13
 
11
14
  /** Shows dialog to select id columns list and seq column, builds and downloads FASTA content */
12
- export function saveAsFastaUI() {
15
+ export function saveAsFastaUI(): void {
13
16
  // Use grid for column order adjusted by user
14
17
  const grid: DG.Grid = grok.shell.tv.grid;
15
18
 
@@ -20,23 +23,27 @@ export function saveAsFastaUI() {
20
23
  .find((gcol: DG.GridColumn) => gcol.name.toLowerCase().indexOf('id') !== -1);
21
24
  const idDefaultValue = defaultIdGCol ? [defaultIdGCol.name] : [];
22
25
 
23
- const idGColListInput = ui.input.multiChoice('Seq id columns', {value: idDefaultValue,
24
- items: idGColList.map((gcol: DG.GridColumn) => gcol.name)});
26
+ const idGColListInput = ui.input.multiChoice('Seq id columns', {
27
+ value: idDefaultValue,
28
+ items: idGColList.map((gcol: DG.GridColumn) => gcol.name)
29
+ });
25
30
 
26
31
  const seqGColList: DG.GridColumn[] = wu.count(0).take(grid.columns.length)/* range rom 0 to grid.columns.length */
27
32
  .map((colI: number) => grid.columns.byIndex(colI)!)
28
33
  .filter((gc: DG.GridColumn) => {
29
34
  const col: DG.Column | null = gc.column;
30
35
  if (col && col.semType === DG.SEMTYPE.MACROMOLECULE) {
31
- const sh = SeqHandler.forColumn(col);
36
+ const sh = _package.seqHelper.getSeqHandler(col);
32
37
  return sh.isFasta();
33
38
  }
34
39
  return false;
35
40
  }).toArray();
36
41
 
37
42
  const seqDefaultValue = seqGColList.length > 0 ? seqGColList[0].name : [];
38
- const seqColInput = ui.input.choice('Seq column', {value: seqDefaultValue,
39
- items: seqGColList.map((gCol: DG.GridColumn) => gCol.name)});
43
+ const seqColInput = ui.input.choice('Seq column', {
44
+ value: seqDefaultValue,
45
+ items: seqGColList.map((gCol: DG.GridColumn) => gCol.name)
46
+ });
40
47
 
41
48
  const lineWidthInput = ui.input.int('FASTA line width', {value: FASTA_LINE_WIDTH});
42
49
 
@@ -56,7 +63,8 @@ export function saveAsFastaUI() {
56
63
  if (!valueSeqCol)
57
64
  grok.shell.warning(`Seq column is mandatory to save as FASTA.`);
58
65
 
59
- const resFastaTxt: string = saveAsFastaDo(valueIdColList, valueSeqCol!, valueLineWidth);
66
+ const seqHandler = _package.seqHelper.getSeqHandler(valueSeqCol!);
67
+ const resFastaTxt: string = saveAsFastaDo(valueIdColList, seqHandler, valueLineWidth);
60
68
 
61
69
  const aEl: HTMLAnchorElement = document.createElement('a');
62
70
  aEl.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(resFastaTxt)}`);
@@ -75,17 +83,16 @@ export function saveAsFastaUI() {
75
83
  * @return {string} FASTA content
76
84
  */
77
85
  export function saveAsFastaDo(
78
- idColList: DG.Column[], seqCol: DG.Column, lineWidth: number = FASTA_LINE_WIDTH, lineSeparator: string = '\n',
86
+ idColList: DG.Column[], seqHandler: ISeqHandler, lineWidth: number = FASTA_LINE_WIDTH, lineSeparator: string = '\n',
79
87
  ): string {
80
- const sh = SeqHandler.forColumn(seqCol);
81
88
  const fastaLines: string[] = [];
82
89
 
83
- for (let rowIdx: number = 0; rowIdx < seqCol.length; rowIdx++) {
90
+ for (let rowIdx: number = 0; rowIdx < seqHandler.length; rowIdx++) {
84
91
  // multiple identifiers separated by vertical bars
85
92
  // https://en.wikipedia.org/wiki/FASTA_format
86
93
 
87
94
  const seqId: string = idColList.map((col) => col.get(rowIdx).toString()).join('|');
88
- const srcSS = sh.getSplitted(rowIdx);
95
+ const srcSS = seqHandler.getSplitted(rowIdx);
89
96
  const seqLineList: string[] = wrapSequence(srcSS, lineWidth);
90
97
 
91
98
  fastaLines.push(`>${seqId}${lineSeparator}`);