@datagrok/bio 2.25.7 → 2.25.9

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.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Davit Rizhinashvili",
6
6
  "email": "drizhinashvili@datagrok.ai"
7
7
  },
8
- "version": "2.25.7",
8
+ "version": "2.25.9",
9
9
  "description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
10
10
  "repository": {
11
11
  "type": "git",
@@ -44,7 +44,7 @@
44
44
  ],
45
45
  "dependencies": {
46
46
  "@biowasm/aioli": "^3.1.0",
47
- "@datagrok-libraries/bio": "^5.61.3",
47
+ "@datagrok-libraries/bio": "^5.61.4",
48
48
  "@datagrok-libraries/chem-meta": "^1.2.9",
49
49
  "@datagrok-libraries/math": "^1.2.6",
50
50
  "@datagrok-libraries/ml": "^6.10.7",
package/src/package.g.ts CHANGED
@@ -310,7 +310,7 @@ export async function toAtomicLevelPanel(sequence: DG.SemanticValue) : Promise<a
310
310
  //name: To Atomic Level Single sequence
311
311
  //description: Converts a single sequence to molblock
312
312
  //input: string sequence { semType: Macromolecule }
313
- //output: string result
313
+ //output: string molfile { semType: Molecule }
314
314
  export async function toAtomicLevelSingleSeq(sequence: string) : Promise<string> {
315
315
  return await PackageFunctions.toAtomicLevelSingleSeq(sequence);
316
316
  }
package/src/package.ts CHANGED
@@ -706,7 +706,8 @@ export class PackageFunctions {
706
706
 
707
707
  @grok.decorators.func({
708
708
  name: 'To Atomic Level Single sequence',
709
- description: 'Converts a single sequence to molblock'
709
+ description: 'Converts a single sequence to molblock',
710
+ outputs: [{name: 'molfile', type: 'string', options: {semType: 'Molecule'}}]
710
711
  })
711
712
  static async toAtomicLevelSingleSeq(
712
713
  @grok.decorators.param({name: 'sequence', type: 'string', options: {semType: 'Macromolecule'}}) sequence: string,
@@ -62,7 +62,7 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
62
62
  set calculating(value: boolean) { this.loader.style.display = value ? 'initial' : 'none'; }
63
63
 
64
64
  get filterSummary(): string {
65
- return this.bioFilter!.filterSummary;
65
+ return this.bioFilter?.filterSummary ?? '';
66
66
  }
67
67
 
68
68
  get isFiltering(): boolean {
@@ -108,6 +108,9 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
108
108
  const superAttach = super.attach.bind(this);
109
109
  const logPrefix = `${this.filterToLog()}.attach()`;
110
110
  this.filterSyncer.sync(logPrefix, async () => {
111
+ // make sure semtypes are detected
112
+ if (dataFrame)
113
+ await dataFrame.meta.detectSemanticTypes();
111
114
  superAttach(dataFrame);
112
115
 
113
116
  if (!this.column) {
@@ -116,18 +119,18 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
116
119
  else
117
120
  this.column = dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
118
121
  }
119
- const sh = this.seqHelper.getSeqHandler(this.column!);
122
+ const _sh = this.seqHelper.getSeqHandler(this.column!);
120
123
  this.columnName ??= this.column?.name;
121
124
  this.notation ??= this.column?.meta.units!;
122
125
 
123
126
  this.bioFilter = this.notation === NOTATION.FASTA ?
124
127
  new FastaBioFilter() : this.notation === NOTATION.SEPARATOR ?
125
128
  new SeparatorBioFilter(this.column!.getTag(bioTAGS.separator)) : new HelmBioFilter(this.seqHelper);
126
- this.root.appendChild(this.bioFilter!.filterPanel);
129
+ this.root.appendChild(this.bioFilter.filterPanel);
127
130
  this.root.appendChild(this.loader);
128
131
  await this.bioFilter.attach(); // may await waitForElementInDom
129
132
 
130
- this.viewSubs.push(DG.debounce(this.bioFilter!.onChanged, this.debounceTime)
133
+ this.viewSubs.push(DG.debounce(this.bioFilter.onChanged, this.debounceTime)
131
134
  .subscribe(this.bioFilterOnChangedDebounced.bind(this)));
132
135
  this.viewSubs.push(grok.events.onResetFilterRequest
133
136
  .subscribe(this.grokEventsOnResetFilterRequest.bind(this)));
@@ -151,10 +154,10 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
151
154
  // -- Sync -
152
155
 
153
156
  private filterOnSync(state: FilterState): void {
154
- if (state.filterId === this.filterId) return;
157
+ if (state.filterId === this.filterId || !this.bioFilter) return;
155
158
  if (state.dataFrameId !== this.dataFrame!.id || state.columnName !== this.columnName) return;
156
159
 
157
- this.bioFilter!.props = state.props;
160
+ this.bioFilter.props = state.props;
158
161
  }
159
162
 
160
163
  // -- Layout --
@@ -173,7 +176,8 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
173
176
  const logPrefix = `${this.filterToLog()}.saveState()`;
174
177
  const state = super.saveState();
175
178
  this.logger.debug(`${logPrefix}, super.state = ${JSON.stringify(state)}`);
176
- state.props = this.bioFilter!.saveProps();
179
+ if (this.bioFilter)
180
+ state.props = this.bioFilter.saveProps();
177
181
  return state;
178
182
  }
179
183
 
@@ -194,10 +198,12 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
194
198
  const logPrefix = `${this.filterToLog()}.fireFilterSync()`;
195
199
  this.logger.debug(`${logPrefix}, ` +
196
200
  `bioFilter = ${!!this.bioFilter ? this.bioFilter.constructor.name : 'null'}` +
197
- (!!this.bioFilter ? `, props = ${JSON.stringify(this.bioFilter!.saveProps())}` : ''));
201
+ (!!this.bioFilter ? `, props = ${JSON.stringify(this.bioFilter.saveProps())}` : ''));
198
202
 
203
+ if (!this.bioFilter)
204
+ return;
199
205
  grok.events.fireCustomEvent(FILTER_SYNC_EVENT, new FilterState(
200
- this.bioFilter!.props, this.filterId, this.dataFrame!.id, this.columnName!, this.bitset));
206
+ this.bioFilter.props, this.filterId, this.dataFrame!.id, this.columnName!, this.bitset));
201
207
  }
202
208
 
203
209
  // -- Handle events
@@ -212,7 +218,7 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
212
218
  const logPrefix = `${this.filterToLog()}.bioFilterOnChangedDebounced()`;
213
219
  this.logger.debug(`${logPrefix}, start, ` +
214
220
  `isFiltering = ${this.isFiltering}, ` +
215
- `props = ${JSON.stringify(this.bioFilter!.saveProps())}`);
221
+ `props = ${this.bioFilter ? JSON.stringify(this.bioFilter?.saveProps()) : 'null'}`);
216
222
 
217
223
  if (!this.isFiltering) {
218
224
  this.bitset = null;
@@ -324,7 +324,9 @@ class LazyConservationTrack extends ConservationTrack {
324
324
  // ============================================================================
325
325
 
326
326
  export const MSA_HEADER_INITIALIZED_FLAG = '__msa-scroller-initialized';
327
- export const MSA_SCROLLER_GRID_SUBSCRIPTION = '__msa-scroller-subscription';
327
+ export const MSA_SCROLLER_GRID_SUBSCRIPTIONS = '__msa-scroller-subscription';
328
+
329
+ type Unsubscibable = { unsubscribe: () => void };
328
330
 
329
331
  export function handleSequenceHeaderRendering() {
330
332
  const handleGrid = (grid: DG.Grid) => {
@@ -334,19 +336,26 @@ export function handleSequenceHeaderRendering() {
334
336
  const df = grid.dataFrame;
335
337
  if (!df) return;
336
338
 
337
- const seqCols = df.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
339
+ if (!grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTIONS])
340
+ grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTIONS] = [] as Unsubscibable[];
341
+ let headerSubs = grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTIONS] as Unsubscibable[];
342
+ headerSubs.forEach((s) => s.unsubscribe());
343
+ grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTIONS] = headerSubs = [];
338
344
 
339
- grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTION]?.unsubscribe();
340
- grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTION] = DG.debounce(rxjs.merge(df.onColumnsAdded, df.onSemanticTypeDetected), 200).subscribe(() => handleGrid(grid));
341
- grid.sub(grid.temp[MSA_SCROLLER_GRID_SUBSCRIPTION]);
345
+ const sub = (s: Unsubscibable) => {
346
+ headerSubs.push(s);
347
+ };
348
+ const seqCols = df.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
349
+ sub(DG.debounce(rxjs.merge(df.onColumnsAdded, df.onColumnsRemoved, df.onSemanticTypeDetected, grid.onEvent('d4-data-frame-changed')), 200).subscribe(() => handleGrid(grid)));
342
350
 
343
351
  for (const seqCol of seqCols) {
344
352
  // first check if the column was already processed
345
353
  const gCol = grid.col(seqCol.name);
346
354
  if (!gCol) continue;
347
355
 
348
- if (gCol.temp[MSA_HEADER_INITIALIZED_FLAG])
349
- continue;
356
+ // if (gCol.temp[MSA_HEADER_INITIALIZED_FLAG])
357
+ // continue;
358
+ const wasInitialized = gCol.temp[MSA_HEADER_INITIALIZED_FLAG] === true;
350
359
  gCol.temp[MSA_HEADER_INITIALIZED_FLAG] = true;
351
360
 
352
361
 
@@ -428,7 +437,7 @@ export function handleSequenceHeaderRendering() {
428
437
  }, 50);
429
438
  });
430
439
 
431
- grid.sub(filterChangeSub);
440
+ sub(filterChangeSub);
432
441
 
433
442
  const initializeHeaders = (monomerLib: IMonomerLib) => {
434
443
  const tracks: { id: string, track: MSAHeaderTrack, priority: number }[] = [];
@@ -501,7 +510,7 @@ export function handleSequenceHeaderRendering() {
501
510
 
502
511
  scroller.setSelectionData(df, seqCol, sh);
503
512
 
504
- if (maxSeqLen > 50) {
513
+ if (maxSeqLen > 50 && !wasInitialized) {
505
514
  grid.props.colHeaderHeight = initialHeaderHeight;
506
515
 
507
516
  // Set column width
@@ -511,10 +520,12 @@ export function handleSequenceHeaderRendering() {
511
520
  }, 300);
512
521
  }
513
522
 
523
+ sub({unsubscribe: () => scroller.detach()}); // Ensure proper cleanup
514
524
  // Handle cell rendering for MSA
515
- grid.sub(grid.onCellRender.subscribe((e) => {
525
+ const tableCol = gCol.column;
526
+ sub(grid.onCellRender.subscribe((e) => {
516
527
  const cell = e.cell;
517
- if (!cell || !cell.isColHeader || cell?.gridColumn?.name !== gCol?.name)
528
+ if (!cell || !cell.isColHeader || cell?.tableColumn?.dart !== tableCol?.dart)
518
529
  return;
519
530
 
520
531
  const cellBounds = e.bounds;