@datagrok/bio 2.11.42 → 2.12.1

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 (61) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/detectors.js +11 -11
  4. package/dist/36.js +1 -1
  5. package/dist/36.js.map +1 -1
  6. package/dist/413.js +1 -1
  7. package/dist/413.js.map +1 -1
  8. package/dist/590.js +1 -1
  9. package/dist/590.js.map +1 -1
  10. package/dist/709.js +1 -1
  11. package/dist/709.js.map +1 -1
  12. package/dist/895.js +1 -1
  13. package/dist/895.js.map +1 -1
  14. package/dist/package-test.js +3 -3
  15. package/dist/package-test.js.map +1 -1
  16. package/dist/package.js +2 -2
  17. package/dist/package.js.map +1 -1
  18. package/files/tests/libraries/HELMmonomerSchema.json +1 -1
  19. package/package.json +11 -11
  20. package/src/analysis/sequence-activity-cliffs.ts +9 -9
  21. package/src/analysis/sequence-diversity-viewer.ts +3 -3
  22. package/src/analysis/sequence-search-base-viewer.ts +2 -2
  23. package/src/analysis/sequence-similarity-viewer.ts +10 -10
  24. package/src/analysis/sequence-space.ts +26 -23
  25. package/src/calculations/monomerLevelMols.ts +13 -11
  26. package/src/package.ts +12 -15
  27. package/src/tests/WebLogo-layout-tests.ts +5 -2
  28. package/src/tests/WebLogo-positions-test.ts +5 -5
  29. package/src/tests/bio-tests.ts +13 -6
  30. package/src/tests/converters-test.ts +4 -4
  31. package/src/tests/detectors-benchmark-tests.ts +5 -5
  32. package/src/tests/detectors-tests.ts +13 -13
  33. package/src/tests/fasta-export-tests.ts +10 -4
  34. package/src/tests/mm-distance-tests.ts +10 -10
  35. package/src/tests/msa-tests.ts +8 -15
  36. package/src/tests/renderers-monomer-placer.ts +3 -3
  37. package/src/tests/renderers-test.ts +6 -8
  38. package/src/tests/splitters-test.ts +14 -13
  39. package/src/tests/substructure-filters-tests.ts +143 -1
  40. package/src/tests/to-atomic-level-tests.ts +2 -2
  41. package/src/tests/units-handler-get-region.ts +4 -4
  42. package/src/tests/units-handler-splitted-tests.ts +19 -17
  43. package/src/tests/units-handler-tests.ts +32 -32
  44. package/src/utils/cell-renderer.ts +40 -34
  45. package/src/utils/check-input-column.ts +5 -5
  46. package/src/utils/context-menu.ts +9 -6
  47. package/src/utils/convert.ts +9 -9
  48. package/src/utils/get-region-func-editor.ts +11 -11
  49. package/src/utils/get-region.ts +10 -12
  50. package/src/utils/macromolecule-column-widget.ts +4 -3
  51. package/src/utils/monomer-lib/library-file-manager/event-manager.ts +1 -1
  52. package/src/utils/multiple-sequence-alignment-ui.ts +6 -6
  53. package/src/utils/pepsea.ts +1 -0
  54. package/src/utils/poly-tool/transformation.ts +3 -3
  55. package/src/utils/poly-tool/ui.ts +46 -135
  56. package/src/utils/save-as-fasta.ts +14 -15
  57. package/src/utils/sequence-to-mol.ts +4 -4
  58. package/src/viewers/web-logo-viewer.ts +46 -54
  59. package/src/widgets/bio-substructure-filter-types.ts +19 -45
  60. package/src/widgets/bio-substructure-filter.ts +45 -23
  61. package/src/widgets/composition-analysis-widget.ts +8 -8
@@ -6,50 +6,24 @@ import {Observable, Subject, Unsubscribable} from 'rxjs';
6
6
  import {_package} from '../package';
7
7
 
8
8
  export interface IFilterProps {
9
- get onChanged(): Observable<void>;
10
-
11
- save(): object;
12
- apply(propsObj: object): void;
13
9
  }
14
10
 
15
11
  /** Fasta and Helm */
16
12
  export class BioFilterProps implements IFilterProps {
17
- private _onChanged: Subject<void> = new Subject<void>();
18
-
19
- get onChanged(): Observable<void> { return this._onChanged; }
20
-
21
13
  constructor(
22
- public substructure: string
14
+ public readonly substructure: string,
15
+ /** Pass false from an inheritors constructor, at the end set true. */ protected readOnly: boolean = true,
23
16
  ) {
24
17
  return new Proxy(this, {
25
18
  set: (target: any, key: string | symbol, value: any) => {
26
19
  _package.logger.debug(`BioFilterProps.set ${key.toString()}( '${value}' )`);
20
+ if (this.readOnly)
21
+ throw new Error('Properties are immutable.');
27
22
  target[key] = value;
28
- this._onChanged.next();
29
23
  return true;
30
24
  }
31
25
  });
32
26
  }
33
-
34
- save(): object {
35
- const propsObj = {};
36
- for (const [key, value] of Object.entries(this)) {
37
- if (key !== '_onChanged') {
38
- // @ts-ignore
39
- propsObj[key] = this[key];
40
- }
41
- }
42
- return propsObj;
43
- }
44
-
45
- apply(propsObj: object) {
46
- for (const [key, value] of Object.entries(this)) {
47
- if (key !== '_onChanged') {
48
- // @ts-ignore
49
- this[key] = propsObj[key];
50
- }
51
- }
52
- }
53
27
  }
54
28
 
55
29
  export interface IBioFilter {
@@ -58,6 +32,9 @@ export interface IBioFilter {
58
32
  get props(): IFilterProps;
59
33
  set props(value: IFilterProps);
60
34
 
35
+ applyProps(props: IFilterProps): void;
36
+ saveProps(): IFilterProps;
37
+
61
38
  get onChanged(): Observable<void>;
62
39
  get filterPanel(): HTMLElement;
63
40
  get filterSummary(): string;
@@ -79,7 +56,6 @@ export abstract class BioFilterBase<TProps extends BioFilterProps> implements IB
79
56
 
80
57
  private _props: TProps;
81
58
  protected _propsChanging: boolean = false;
82
- private _propsOnChangedSub: Unsubscribable | null = null;
83
59
 
84
60
  abstract get type(): string;
85
61
 
@@ -91,33 +67,31 @@ export abstract class BioFilterBase<TProps extends BioFilterProps> implements IB
91
67
  set props(value: TProps) {
92
68
  this._propsChanging = true;
93
69
  try {
94
- if (this._propsOnChangedSub) {
95
- this._propsOnChangedSub.unsubscribe();
96
- this._propsOnChangedSub = null;
97
- }
98
70
  this._props = value;
99
71
  this.applyProps();
100
72
  this.onChanged.next();
101
- this._propsOnChangedSub = this._props.onChanged
102
- .subscribe(() => {
103
- this.onChanged.next();
104
- });
105
73
  } finally {
106
74
  this._propsChanging = false;
107
75
  }
108
76
  };
109
77
 
110
- abstract attach(): Promise<void>;
111
-
112
- async detach(): Promise<void> {
113
- if (this._propsOnChangedSub) {
114
- this._propsOnChangedSub.unsubscribe();
115
- this._propsOnChangedSub = null;
78
+ saveProps(): IFilterProps {
79
+ const propsObj = {};
80
+ for (const [key, value] of Object.entries(this.props)) {
81
+ if (key !== '_onChanged') {
82
+ // @ts-ignore
83
+ propsObj[key] = this.props[key];
84
+ }
116
85
  }
86
+ return propsObj;
117
87
  }
118
88
 
119
89
  abstract applyProps(): void;
120
90
 
91
+ abstract attach(): Promise<void>;
92
+
93
+ async detach(): Promise<void> { }
94
+
121
95
  get filterSummary(): string { return this.props.substructure; };
122
96
 
123
97
  get isFiltering(): boolean { return this.props.substructure !== ''; }
@@ -10,14 +10,14 @@ import * as grok from 'datagrok-api/grok';
10
10
 
11
11
  import wu from 'wu';
12
12
  import $ from 'cash-dom';
13
- import {fromEvent, Observable, Subject, Subscription, Unsubscribable} from 'rxjs';
13
+ import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
14
14
 
15
15
  import {TAGS as bioTAGS, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
16
16
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
17
17
  import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
18
18
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
19
19
  import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
20
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
20
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
21
21
  import {IRenderer} from '@datagrok-libraries/bio/src/types/renderer';
22
22
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
23
23
  import {PromiseSyncer} from '@datagrok-libraries/bio/src/utils/syncer';
@@ -44,9 +44,10 @@ class FilterState {
44
44
  export class SeparatorFilterProps extends BioFilterProps {
45
45
  constructor(
46
46
  substructure: string,
47
- public separator?: string
47
+ public readonly separator?: string,
48
48
  ) {
49
- super(substructure);
49
+ super(substructure, false);
50
+ this.readOnly = true;
50
51
  }
51
52
  }
52
53
 
@@ -119,8 +120,14 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
119
120
  const logPrefix = `${this.filterToLog()}.attach()`;
120
121
  this.filterSyncer.sync(logPrefix, async () => {
121
122
  superAttach(dataFrame);
122
- this.column = dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
123
- const uh = UnitsHandler.getOrCreate(this.column!);
123
+
124
+ if (!this.column) {
125
+ if (this.columnName)
126
+ this.column = this.dataFrame!.getCol(this.columnName);
127
+ else
128
+ this.column = dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
129
+ }
130
+ const sh = SeqHandler.forColumn(this.column!);
124
131
  this.columnName ??= this.column?.name;
125
132
  this.notation ??= this.column?.getTag(DG.TAGS.UNITS);
126
133
 
@@ -134,7 +141,7 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
134
141
  this.viewSubs.push(DG.debounce(this.bioFilter!.onChanged, this.debounceTime)
135
142
  .subscribe(this.bioFilterOnChangedDebounced.bind(this)));
136
143
  this.viewSubs.push(grok.events.onResetFilterRequest
137
- .subscribe((_value: any) => { this.bioFilter?.resetFilter(); }));
144
+ .subscribe(this.grokEventsOnResetFilterRequest.bind(this)));
138
145
  this.viewSubs.push(grok.events.onCustomEvent(FILTER_SYNC_EVENT)
139
146
  .subscribe(this.filterOnSync.bind(this)));
140
147
  });
@@ -164,6 +171,8 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
164
171
  // -- Layout --
165
172
 
166
173
  applyFilter(): void {
174
+ const logPrefix = `${this.filterToLog()}.applyFilter()`;
175
+ this.logger.debug(`${logPrefix}, IN`);
167
176
  if (this.bitset && !this.isDetached)
168
177
  this.dataFrame?.filter.and(this.bitset);
169
178
  }
@@ -172,8 +181,10 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
172
181
  * @return {any} - filter state
173
182
  */
174
183
  saveState(): any {
184
+ const logPrefix = `${this.filterToLog()}.saveState()`;
175
185
  const state = super.saveState();
176
- state.props = this.bioFilter!.props.save();
186
+ this.logger.debug(`${logPrefix}, super.state = ${JSON.stringify(state)}`);
187
+ state.props = this.bioFilter!.saveProps();
177
188
  return state;
178
189
  }
179
190
 
@@ -181,21 +192,20 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
181
192
  * @param {any} state - filter state
182
193
  */
183
194
  applyState(state: any): void {
195
+ const logPrefix = `${this.filterToLog()}.applyState()`;
184
196
  super.applyState(state); //column, columnName
185
- if (state.props)
186
- this.bioFilter!.props.apply(state.props);
187
197
 
188
- // if (state.bioSubstructure) {
189
- // // (async () => { await this.bioFilterOnChangedDebounced(); })();
190
- // this.bioFilter!.substructure = state.bioSubstructure;
191
- // }
198
+ this.filterSyncer.sync(logPrefix, async () => {
199
+ if (state.props && this.bioFilter)
200
+ this.bioFilter.props = state.props;
201
+ });
192
202
  }
193
203
 
194
204
  private fireFilterSync(): void {
195
205
  const logPrefix = `${this.filterToLog()}.fireFilterSync()`;
196
206
  _package.logger.debug(`${logPrefix}, ` +
197
207
  `bioFilter = ${!!this.bioFilter ? this.bioFilter.constructor.name : 'null'}` +
198
- (!!this.bioFilter ? `, props = ${JSON.stringify(this.bioFilter!.props.save())}` : ''));
208
+ (!!this.bioFilter ? `, props = ${JSON.stringify(this.bioFilter!.saveProps())}` : ''));
199
209
 
200
210
  grok.events.fireCustomEvent(FILTER_SYNC_EVENT, new FilterState(
201
211
  this.bioFilter!.props, this.filterId, this.dataFrame!.id, this.columnName!, this.bitset));
@@ -213,7 +223,7 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
213
223
  const logPrefix = `${this.filterToLog()}.bioFilterOnChangedDebounced()`;
214
224
  _package.logger.debug(`${logPrefix}, start, ` +
215
225
  `isFiltering = ${this.isFiltering}, ` +
216
- `props = ${JSON.stringify(this.bioFilter!.props.save())}`);
226
+ `props = ${JSON.stringify(this.bioFilter!.saveProps())}`);
217
227
 
218
228
  if (!this.isFiltering) {
219
229
  this.bitset = null;
@@ -241,6 +251,12 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
241
251
  });
242
252
  }
243
253
 
254
+ grokEventsOnResetFilterRequest(): void {
255
+ const logPrefix = `${this.filterToLog()}.grokEventsOnResetFilterRequest()`;
256
+ _package.logger.debug(`${logPrefix}`);
257
+ this.bioFilter?.resetFilter();
258
+ }
259
+
244
260
  // -- IRenderer --
245
261
 
246
262
  private _onRendered = new Subject<void>();
@@ -282,13 +298,14 @@ export class FastaBioFilter extends BioFilterBase<BioFilterProps> {
282
298
  super();
283
299
 
284
300
  this.substructureInput = ui.stringInput('', '', () => {
285
- this.props.substructure = this.substructureInput.value;
301
+ this.props = new BioFilterProps(this.substructureInput.value);
286
302
  if (!this._propsChanging) this.onChanged.next();
287
303
  }, {placeholder: 'Substructure'});
288
304
  }
289
305
 
290
306
  public applyProps() {
291
- this.substructureInput.value = this.props.substructure;
307
+ if (this.substructureInput.value !== this.props.substructure)
308
+ this.substructureInput.value = this.props.substructure;
292
309
  }
293
310
 
294
311
  get filterPanel() {
@@ -309,7 +326,7 @@ export class FastaBioFilter extends BioFilterBase<BioFilterProps> {
309
326
  }
310
327
 
311
328
  export class SeparatorBioFilter extends BioFilterBase<SeparatorFilterProps> {
312
- readonly emptyProps = new SeparatorFilterProps('');
329
+ readonly emptyProps = new SeparatorFilterProps('', undefined);
313
330
 
314
331
  readonly substructureInput: DG.InputBase<string>;
315
332
  readonly separatorInput: DG.InputBase<string>;
@@ -321,18 +338,23 @@ export class SeparatorBioFilter extends BioFilterBase<SeparatorFilterProps> {
321
338
  super();
322
339
 
323
340
  this.substructureInput = ui.stringInput('', '', () => {
324
- this.props.substructure = this.substructureInput.value;
341
+ this.props = new SeparatorFilterProps(this.substructureInput.value, this.props.separator);
325
342
  if (!this._propsChanging) this.onChanged.next();
326
343
  }, {placeholder: 'Substructure'});
327
344
  this.separatorInput = ui.stringInput('', this.colSeparator = colSeparator, () => {
328
- this.props.separator = !!this.separatorInput.value ? this.separatorInput.value : undefined;
345
+ const separator: string | undefined = !!this.separatorInput.value ? this.separatorInput.value : undefined;
346
+ this.props = new SeparatorFilterProps(this.props.substructure, separator);
329
347
  if (!this._propsChanging) this.onChanged.next();
330
348
  }, {placeholder: 'Separator'});
331
349
  }
332
350
 
333
351
  applyProps(): void {
334
- this.substructureInput.value = this.props.substructure;
335
- this.separatorInput.value = this.props.separator ?? this.colSeparator;
352
+ if (this.substructureInput.value !== this.props.substructure)
353
+ this.substructureInput.value = this.props.substructure;
354
+
355
+ const separatorValue = this.props.separator ?? this.colSeparator;
356
+ if (this.separatorInput.value !== separatorValue)
357
+ this.separatorInput.value = separatorValue;
336
358
  }
337
359
 
338
360
  get filterSummary(): string {
@@ -8,8 +8,8 @@ import {TAGS as bioTAGS, ALPHABET, getPaletteByType} from '@datagrok-libraries/b
8
8
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
9
9
  import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
10
10
  import '../../css/composition-analysis.css';
11
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
12
- import {GAP_SYMBOL} from '../const';
11
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
12
+ import {GAP_SYMBOL} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
13
13
 
14
14
 
15
15
  export function getCompositionAnalysisWidget(val: DG.SemanticValue): DG.Widget {
@@ -30,12 +30,12 @@ export function getCompositionAnalysisWidget(val: DG.SemanticValue): DG.Widget {
30
30
  }
31
31
 
32
32
  const counts: { [m: string]: number } = {};
33
- const uh = UnitsHandler.getOrCreate(val.cell.column);
34
- const splitter = uh.getSplitter();
35
- const parts = splitter(val.value);
36
- wu(parts).filter((p) => !!p && p !== '').forEach((m: string) => {
37
- const count = counts[m] || 0;
38
- counts[m] = count + 1;
33
+ const sh = SeqHandler.forColumn(val.cell.column as DG.Column<string>);
34
+ const rowIdx = val.cell.rowIndex;
35
+ const parts = sh.getSplitted(rowIdx);
36
+ wu(parts.canonicals).filter((cm) => cm !== GAP_SYMBOL).forEach((cm) => {
37
+ const count = counts[cm] || 0;
38
+ counts[cm] = count + 1;
39
39
  });
40
40
  const table = buildCompositionTable(palette, counts);
41
41
  Array.from(table.rows).forEach((row) => {