@datagrok/bio 2.4.31 → 2.4.39

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 (99) hide show
  1. package/.eslintrc.json +6 -8
  2. package/README.md +22 -7
  3. package/detectors.js +21 -12
  4. package/dist/1.js +2 -0
  5. package/dist/1.js.map +1 -0
  6. package/dist/18.js +2 -0
  7. package/dist/18.js.map +1 -0
  8. package/dist/190.js +2 -0
  9. package/dist/190.js.map +1 -0
  10. package/dist/452.js +2 -0
  11. package/dist/452.js.map +1 -0
  12. package/dist/729.js +2 -0
  13. package/dist/729.js.map +1 -0
  14. package/dist/package-test.js +1 -1
  15. package/dist/package-test.js.map +1 -1
  16. package/dist/package.js +1 -1
  17. package/dist/package.js.map +1 -1
  18. package/files/libraries/broken-lib.sdf +136 -0
  19. package/files/libraries/group1/mock-lib-3.json +74 -0
  20. package/files/libraries/mock-lib-2.json +48 -0
  21. package/files/tests/100_3_clustests.csv +100 -0
  22. package/files/tests/100_3_clustests_empty_vals.csv +100 -0
  23. package/files/tests/peptides_motif-with-random_10000.csv +9998 -0
  24. package/package.json +4 -4
  25. package/scripts/sequence_generator.py +164 -48
  26. package/src/analysis/sequence-activity-cliffs.ts +7 -9
  27. package/src/analysis/sequence-diversity-viewer.ts +8 -3
  28. package/src/analysis/sequence-search-base-viewer.ts +4 -3
  29. package/src/analysis/sequence-similarity-viewer.ts +13 -7
  30. package/src/analysis/sequence-space.ts +15 -12
  31. package/src/analysis/workers/mm-distance-array-service.ts +48 -0
  32. package/src/analysis/workers/mm-distance-array-worker.ts +29 -0
  33. package/src/analysis/workers/mm-distance-worker-creator.ts +6 -9
  34. package/src/apps/web-logo-app.ts +34 -0
  35. package/src/calculations/monomerLevelMols.ts +10 -12
  36. package/src/demo/bio01-similarity-diversity.ts +4 -5
  37. package/src/demo/bio01a-hierarchical-clustering-and-sequence-space.ts +6 -7
  38. package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +7 -8
  39. package/src/demo/bio03-atomic-level.ts +1 -4
  40. package/src/demo/bio05-helm-msa-sequence-space.ts +6 -4
  41. package/src/demo/utils.ts +3 -4
  42. package/src/package-test.ts +1 -2
  43. package/src/package.ts +135 -82
  44. package/src/seq_align.ts +482 -483
  45. package/src/substructure-search/substructure-search.ts +3 -3
  46. package/src/tests/Palettes-test.ts +1 -1
  47. package/src/tests/WebLogo-positions-test.ts +12 -35
  48. package/src/tests/_first-tests.ts +1 -1
  49. package/src/tests/activity-cliffs-tests.ts +10 -7
  50. package/src/tests/activity-cliffs-utils.ts +6 -5
  51. package/src/tests/bio-tests.ts +20 -25
  52. package/src/tests/checkInputColumn-tests.ts +5 -11
  53. package/src/tests/converters-test.ts +19 -37
  54. package/src/tests/detectors-benchmark-tests.ts +35 -37
  55. package/src/tests/detectors-tests.ts +29 -34
  56. package/src/tests/detectors-weak-and-likely-tests.ts +11 -21
  57. package/src/tests/fasta-export-tests.ts +3 -3
  58. package/src/tests/fasta-handler-test.ts +2 -3
  59. package/src/tests/lib-tests.ts +2 -4
  60. package/src/tests/mm-distance-tests.ts +25 -17
  61. package/src/tests/monomer-libraries-tests.ts +1 -1
  62. package/src/tests/msa-tests.ts +12 -9
  63. package/src/tests/pepsea-tests.ts +6 -3
  64. package/src/tests/renderers-test.ts +13 -11
  65. package/src/tests/sequence-space-test.ts +10 -8
  66. package/src/tests/sequence-space-utils.ts +6 -4
  67. package/src/tests/similarity-diversity-tests.ts +47 -61
  68. package/src/tests/splitters-test.ts +14 -20
  69. package/src/tests/to-atomic-level-tests.ts +9 -17
  70. package/src/tests/units-handler-splitted-tests.ts +106 -0
  71. package/src/tests/units-handler-tests.ts +22 -26
  72. package/src/tests/utils/sequences-generators.ts +6 -2
  73. package/src/tests/utils.ts +10 -4
  74. package/src/tests/viewers.ts +1 -1
  75. package/src/utils/atomic-works.ts +49 -57
  76. package/src/utils/cell-renderer.ts +25 -8
  77. package/src/utils/check-input-column.ts +19 -4
  78. package/src/utils/constants.ts +3 -3
  79. package/src/utils/convert.ts +56 -23
  80. package/src/utils/monomer-lib.ts +83 -64
  81. package/src/utils/multiple-sequence-alignment-ui.ts +24 -21
  82. package/src/utils/multiple-sequence-alignment.ts +2 -2
  83. package/src/utils/pepsea.ts +17 -7
  84. package/src/utils/save-as-fasta.ts +11 -4
  85. package/src/utils/ui-utils.ts +1 -1
  86. package/src/viewers/vd-regions-viewer.ts +21 -22
  87. package/src/viewers/web-logo-viewer.ts +189 -154
  88. package/src/widgets/bio-substructure-filter.ts +9 -6
  89. package/src/widgets/representations.ts +11 -12
  90. package/tsconfig.json +1 -1
  91. package/dist/258.js +0 -2
  92. package/dist/258.js.map +0 -1
  93. package/dist/457.js +0 -2
  94. package/dist/457.js.map +0 -1
  95. package/dist/562.js +0 -2
  96. package/dist/562.js.map +0 -1
  97. package/dist/925.js +0 -2
  98. package/dist/925.js.map +0 -1
  99. package/src/analysis/workers/mm-distance-worker.ts +0 -16
@@ -10,10 +10,10 @@ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
10
10
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
11
11
  import {
12
12
  getSplitter, monomerToShort, pickUpPalette, pickUpSeqCol, SplitterFunc,
13
- TAGS as bioTAGS
13
+ TAGS as bioTAGS,
14
14
  } from '@datagrok-libraries/bio/src/utils/macromolecule';
15
15
  import {
16
- WebLogoPropsDefault, WebLogoProps, IWebLogoViewer,
16
+ WebLogoPropsDefault, WebLogoProps,
17
17
  PositionHeight,
18
18
  positionSeparator,
19
19
  VerticalAlignments,
@@ -23,6 +23,7 @@ import {
23
23
  } from '@datagrok-libraries/bio/src/viewers/web-logo';
24
24
  import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
25
25
  import {TAGS as wlTAGS} from '@datagrok-libraries/bio/src/viewers/web-logo';
26
+ import {_package} from '../package';
26
27
 
27
28
  declare global {
28
29
  interface HTMLCanvasElement {
@@ -68,13 +69,14 @@ export class PositionInfo {
68
69
  sumForHeightCalc: number;
69
70
 
70
71
  /** freq = {}, rowCount = 0
72
+ * @param {number} pos Position in sequence
71
73
  * @param {string} name Name of position ('111A', '111.1', etc)
72
- * @param {number} sumForHeightCalc Sum of all monomer counts for height calculation
73
- * @param {number} rowCount Count of elements in column
74
74
  * @param {string[]} freq frequency of monomers in position
75
+ * @param {number} rowCount Count of elements in column
76
+ * @param {number} sumForHeightCalc Sum of all monomer counts for height calculation
75
77
  */
76
78
  constructor(pos: number, name: string,
77
- freq: { [m: string]: PositionMonomerInfo } = {}, rowCount: number = 0, sumForHeightCalc: number = 0
79
+ freq: { [m: string]: PositionMonomerInfo } = {}, rowCount: number = 0, sumForHeightCalc: number = 0,
78
80
  ) {
79
81
  this.pos = pos;
80
82
  this.name = name;
@@ -125,6 +127,8 @@ export class WebLogoViewer extends DG.JsViewer {
125
127
  public static residuesSet = 'nucleotides';
126
128
  private static viewerCount: number = -1;
127
129
 
130
+ private viewed: boolean = false;
131
+
128
132
  private readonly viewerId: number = -1;
129
133
  private unitsHandler: UnitsHandler | null;
130
134
  private initialized: boolean = false;
@@ -141,7 +145,6 @@ export class WebLogoViewer extends DG.JsViewer {
141
145
  private axisHeight: number = 12;
142
146
 
143
147
  private seqCol: DG.Column<string> | null = null;
144
- private splitter: SplitterFunc | null = null;
145
148
  // private maxLength: number = 100;
146
149
  private positions: PositionInfo[] = [];
147
150
 
@@ -184,21 +187,21 @@ export class WebLogoViewer extends DG.JsViewer {
184
187
  private get filter(): DG.BitSet {
185
188
  let res: DG.BitSet;
186
189
  switch (this.filterSource) {
187
- case FilterSources.Filtered:
188
- res = this.dataFrame.filter;
189
- break;
190
- case FilterSources.Selected:
191
- res = this.dataFrame.selection;
192
- break;
190
+ case FilterSources.Filtered:
191
+ res = this.dataFrame.filter;
192
+ break;
193
+ case FilterSources.Selected:
194
+ res = this.dataFrame.selection;
195
+ break;
193
196
  }
194
197
  return res;
195
198
  }
196
199
 
197
200
  /** For startPosition equals to endPosition Length is 1 */
198
201
  private get Length(): number {
199
- if (this.skipEmptyPositions) {
202
+ if (this.skipEmptyPositions)
200
203
  return this.positions.length;
201
- }
204
+
202
205
  return this.startPosition <= this.endPosition ? this.endPosition - this.startPosition + 1 : 0;
203
206
  }
204
207
 
@@ -208,27 +211,26 @@ export class WebLogoViewer extends DG.JsViewer {
208
211
  }
209
212
 
210
213
  private get positionMarginValue() {
211
- if ((this.positionMarginState === 'auto') && (this.unitsHandler?.getAlphabetIsMultichar() === true)) {
214
+ if ((this.positionMarginState === 'auto') && (this.unitsHandler?.getAlphabetIsMultichar() === true))
212
215
  return this.positionMargin;
213
- }
214
- if (this.positionMarginState === 'enable') {
216
+
217
+ if (this.positionMarginState === 'enable')
215
218
  return this.positionMargin;
216
- }
219
+
217
220
 
218
221
  return 0;
219
222
  }
220
223
 
221
224
  /** Count of position rendered for calculations countOfRenderPositions */
222
225
  private get countOfRenderPositions() {
223
- if (this.host == null) {
226
+ if (this.host == null)
224
227
  return 0;
225
- }
228
+
226
229
  const r = window.devicePixelRatio;
227
- if (r > 1) {
230
+ if (r > 1)
228
231
  return this.canvasWidthWithRatio / this.positionWidthWithMargin;
229
- } else {
232
+ else
230
233
  return this.canvas.width / (this.positionWidthWithMargin * r);
231
- }
232
234
  }
233
235
 
234
236
  private get canvasWidthWithRatio() {
@@ -306,7 +308,7 @@ export class WebLogoViewer extends DG.JsViewer {
306
308
 
307
309
  private init(): void {
308
310
  if (this.initialized) {
309
- console.error('Bio: WebLogoViewer.init() second initialization!');
311
+ _package.logger.error('Bio: WebLogoViewer.init() second initialization!');
310
312
  return;
311
313
  }
312
314
 
@@ -353,6 +355,53 @@ export class WebLogoViewer extends DG.JsViewer {
353
355
  this.render(true);
354
356
  }
355
357
 
358
+ // -- Data --
359
+
360
+ setData(): void {
361
+ if (this.viewed) {
362
+ this.destroyView();
363
+ this.viewed = false;
364
+ }
365
+
366
+ this.updateSeqCol();
367
+
368
+ if (!this.viewed) {
369
+ this.buildView();
370
+ this.viewed = true;
371
+ }
372
+ }
373
+
374
+ // -- View --
375
+
376
+ private destroyView() {
377
+ const dataFrameTxt = `${this.dataFrame ? 'data' : 'null'}`;
378
+ _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached( dataFrame = ${dataFrameTxt} ) start`);
379
+ super.detach();
380
+
381
+ this.viewSubs.forEach((sub) => sub.unsubscribe());
382
+ this.host!.remove();
383
+ this.msgHost = undefined;
384
+ this.host = undefined;
385
+
386
+ this.initialized = false;
387
+ _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.destroyView() end`);
388
+ }
389
+
390
+ private buildView() {
391
+ super.onTableAttached();
392
+
393
+ const dataFrameTxt: string = this.dataFrame ? 'data' : 'null';
394
+ _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached( dataFrame = ${dataFrameTxt} ) start`);
395
+
396
+ if (this.dataFrame !== undefined) {
397
+ this.viewSubs.push(this.dataFrame.filter.onChanged.subscribe(this.dataFrameFilterOnChanged.bind(this)));
398
+ this.viewSubs.push(this.dataFrame.selection.onChanged.subscribe(this.dataFrameSelectionOnChanged.bind(this)));
399
+ }
400
+
401
+ this.init();
402
+ _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached() end`);
403
+ }
404
+
356
405
  /** Handler of changing size WebLogo */
357
406
  private rootOnSizeChanged(): void {
358
407
  this._calculate(window.devicePixelRatio);
@@ -370,19 +419,25 @@ export class WebLogoViewer extends DG.JsViewer {
370
419
  this.sequenceColumnName = this.seqCol ? this.seqCol.name : null;
371
420
  }
372
421
  if (this.seqCol) {
373
- const units: string = this.seqCol!.getTag(DG.TAGS.UNITS);
374
- const separator: string = this.seqCol!.getTag(bioTAGS.separator);
375
- this.splitter = getSplitter(units, separator);
376
- this.unitsHandler = new UnitsHandler(this.seqCol);
377
-
378
- this.updatePositions();
379
- this.cp = pickUpPalette(this.seqCol);
380
- } else {
381
- this.splitter = null;
382
- this.positionNames = [];
383
- this.startPosition = -1;
384
- this.endPosition = -1;
385
- this.cp = null;
422
+ try {
423
+ const units: string = this.seqCol!.getTag(DG.TAGS.UNITS);
424
+ const separator: string = this.seqCol!.getTag(bioTAGS.separator);
425
+ this.unitsHandler = UnitsHandler.getOrCreate(this.seqCol);
426
+
427
+ this.updatePositions();
428
+ this.cp = pickUpPalette(this.seqCol);
429
+ } catch (err: any) {
430
+ this.seqCol = null;
431
+ this.msgHost!.innerText = `${err}`;
432
+ this.msgHost!.style.setProperty('display', null);
433
+ }
434
+ if (!this.seqCol) {
435
+ this.unitsHandler = null;
436
+ this.positionNames = [];
437
+ this.startPosition = -1;
438
+ this.endPosition = -1;
439
+ this.cp = null;
440
+ }
386
441
  }
387
442
  }
388
443
  this.render();
@@ -402,8 +457,7 @@ export class WebLogoViewer extends DG.JsViewer {
402
457
  } else {
403
458
  categories = this.seqCol.categories;
404
459
  }
405
- const maxLength = categories.length > 0 ? Math.max(...categories.map(
406
- (s) => s !== null ? this.splitter!(s).length : 0)) : 0;
460
+ const maxLength = categories.length > 0 ? Math.max(...this.unitsHandler!.splitted.map((mList) => mList.length)) : 0;
407
461
 
408
462
  // Get position names from data column tag 'positionNames'
409
463
  const positionNamesTxt = this.seqCol.getTag(wlTAGS.positionNames);
@@ -439,10 +493,11 @@ export class WebLogoViewer extends DG.JsViewer {
439
493
  let showSliderWithFitArea = true;
440
494
  const minScale = Math.min(this.xScale, this.yScale);
441
495
 
442
- if (((minScale == this.xScale) || (minScale <= 1)) && (this.fitArea)) {
496
+ if (((minScale == this.xScale) || (minScale <= 1)) && (this.fitArea))
443
497
  showSliderWithFitArea = false;
444
- }
445
- return ((this.fixWidth || Math.ceil(this.canvas.width / this.positionWidthWithMargin) >= this.Length) || (showSliderWithFitArea));
498
+
499
+ return ((this.fixWidth || Math.ceil(this.canvas.width / this.positionWidthWithMargin) >= this.Length) ||
500
+ (showSliderWithFitArea));
446
501
  }
447
502
 
448
503
  setSliderVisibility(visible: boolean): void {
@@ -457,16 +512,17 @@ export class WebLogoViewer extends DG.JsViewer {
457
512
 
458
513
  /** Updates {@link slider}, needed to set slider options and to update slider position. */
459
514
  private updateSlider(): void {
460
- if (this.checkIsHideSlider()) {
515
+ if (this.checkIsHideSlider())
461
516
  this.setSliderVisibility(false);
462
- } else {
517
+ else
463
518
  this.setSliderVisibility(true);
464
- }
519
+
465
520
  if ((this.slider != null) && (this.canvas != null)) {
466
521
  const diffEndScrollAndSliderMin = Math.max(0,
467
522
  Math.floor(this.slider.min + this.canvas.width / this.positionWidthWithMargin) - this.Length);
468
523
  let newMin = Math.floor(this.slider.min - diffEndScrollAndSliderMin);
469
- let newMax = Math.floor(this.slider.min - diffEndScrollAndSliderMin) + Math.floor(this.canvas.width / this.positionWidthWithMargin);
524
+ let newMax = Math.floor(this.slider.min - diffEndScrollAndSliderMin) +
525
+ Math.floor(this.canvas.width / this.positionWidthWithMargin);
470
526
  if (this.checkIsHideSlider()) {
471
527
  newMin = 0;
472
528
  newMax = Math.max(newMin, this.Length - 1);
@@ -477,30 +533,32 @@ export class WebLogoViewer extends DG.JsViewer {
477
533
  }
478
534
  }
479
535
 
480
- /** Handler of property change events. */
536
+ /** Handler of property change events.
537
+ * @param {DG.Property} property - property which was changed.
538
+ */
481
539
  public override onPropertyChanged(property: DG.Property): void {
482
540
  super.onPropertyChanged(property);
483
541
 
484
542
  switch (property.name) {
485
- case PROPS.sequenceColumnName:
486
- case PROPS.startPositionName:
487
- case PROPS.endPositionName:
488
- case PROPS.filterSource:
489
- this.updateSeqCol();
490
- break;
491
- case PROPS.positionWidth:
492
- this._positionWidth = this.positionWidth;
493
- this.updateSlider();
494
- break;
495
- case PROPS.fixWidth:
496
- case PROPS.fitArea:
497
- case PROPS.positionMargin:
498
- this.updateSlider();
499
- break;
500
- case PROPS.shrinkEmptyTail:
501
- case PROPS.skipEmptyPositions:
502
- this.updatePositions();
503
- break;
543
+ case PROPS.sequenceColumnName:
544
+ case PROPS.startPositionName:
545
+ case PROPS.endPositionName:
546
+ case PROPS.filterSource:
547
+ this.updateSeqCol();
548
+ break;
549
+ case PROPS.positionWidth:
550
+ this._positionWidth = this.positionWidth;
551
+ this.updateSlider();
552
+ break;
553
+ case PROPS.fixWidth:
554
+ case PROPS.fitArea:
555
+ case PROPS.positionMargin:
556
+ this.updateSlider();
557
+ break;
558
+ case PROPS.shrinkEmptyTail:
559
+ case PROPS.skipEmptyPositions:
560
+ this.updatePositions();
561
+ break;
504
562
  }
505
563
 
506
564
  this.render(true);
@@ -508,35 +566,20 @@ export class WebLogoViewer extends DG.JsViewer {
508
566
 
509
567
  /** Add filter handlers when table is a attached */
510
568
  public override onTableAttached() {
511
- super.onTableAttached();
569
+ _package.logger.debug('Bio: WebLogoViewer.onTableAttached(), ');
512
570
 
513
- const dataFrameTxt: string = this.dataFrame ? 'data' : 'null';
514
- console.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached( dataFrame = ${dataFrameTxt} ) start`);
571
+ // -- Props editors --
515
572
 
516
- this.updateSeqCol();
517
-
518
- if (this.dataFrame !== undefined) {
519
- this.viewSubs.push(this.dataFrame.filter.onChanged.subscribe(this.dataFrameFilterOnChanged.bind(this)));
520
- this.viewSubs.push(this.dataFrame.selection.onChanged.subscribe(this.dataFrameSelectionOnChanged.bind(this)));
521
- }
522
-
523
- this.init();
524
- console.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached() end`);
573
+ super.onTableAttached();
574
+ this.setData();
525
575
  }
526
576
 
527
577
  /** Remove all handlers when table is a detach */
528
578
  public override async detach() {
529
- const dataFrameTxt = `${this.dataFrame ? 'data' : 'null'}`;
530
- console.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached( dataFrame = ${dataFrameTxt} ) start`);
531
- super.detach();
532
-
533
- this.viewSubs.forEach((sub) => sub.unsubscribe());
534
- this.host!.remove();
535
- this.msgHost = undefined;
536
- this.host = undefined;
537
-
538
- this.initialized = false;
539
- console.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached() end`);
579
+ if (this.viewed) {
580
+ this.destroyView();
581
+ this.viewed = false;
582
+ }
540
583
  }
541
584
 
542
585
  // -- Routines --
@@ -557,7 +600,10 @@ export class WebLogoViewer extends DG.JsViewer {
557
600
  return [jPos, monomer, position.freq[monomer]];
558
601
  };
559
602
 
560
- /** Helper function for rendering */
603
+ /** Helper function for rendering
604
+ * @param {boolean} fillerResidue
605
+ * @return {string} - string with null sequence
606
+ */
561
607
  protected _nullSequence(fillerResidue = 'X'): string {
562
608
  if (!this.skipEmptySequences)
563
609
  return new Array(this.Length).fill(fillerResidue).join('');
@@ -582,15 +628,14 @@ export class WebLogoViewer extends DG.JsViewer {
582
628
 
583
629
  /** Function for removing empty positions */
584
630
  protected _removeEmptyPositions() {
585
- if (this.skipEmptyPositions) {
631
+ if (this.skipEmptyPositions)
586
632
  this.removeWhere(this.positions, (item) => item?.freq['-']?.count === item.rowCount);
587
- }
588
633
  }
589
634
 
590
635
  protected _calculate(r: number) {
591
636
  if (!this.host || !this.seqCol || !this.dataFrame)
592
637
  return;
593
- this.unitsHandler = new UnitsHandler(this.seqCol);
638
+ this.unitsHandler = UnitsHandler.getOrCreate(this.seqCol);
594
639
 
595
640
  this.calcSize();
596
641
 
@@ -602,22 +647,14 @@ export class WebLogoViewer extends DG.JsViewer {
602
647
  }
603
648
 
604
649
  // 2022-05-05 askalkin instructed to show WebLogo based on filter (not selection)
605
- const indices = this.filter.getSelectedIndexes();
650
+ const selRowIndices = this.filter.getSelectedIndexes();
606
651
  // const indices = this.dataFrame.selection.trueCount > 0 ? this.dataFrame.selection.getSelectedIndexes() :
607
652
  // this.dataFrame.filter.getSelectedIndexes();
608
653
 
609
- this.rowsMasked = indices.length;
610
- this.rowsNull = 0;
611
-
612
- for (const i of indices) {
613
- let s: string = <string>(this.seqCol.get(i));
654
+ this.rowsMasked = selRowIndices.length;
614
655
 
615
- if (!s) {
616
- s = this._nullSequence();
617
- ++this.rowsNull;
618
- }
619
-
620
- const seqM: string[] = this.splitter!(s);
656
+ for (const rowI of selRowIndices) {
657
+ const seqM: string[] = this.unitsHandler.splitted[rowI];
621
658
  for (let jPos = 0; jPos < this.Length; jPos++) {
622
659
  const pmInfo = this.positions[jPos].freq;
623
660
  const m: string = seqM[this.startPosition + jPos] || '-';
@@ -652,9 +689,9 @@ export class WebLogoViewer extends DG.JsViewer {
652
689
  const freq: { [c: string]: PositionMonomerInfo } = this.positions[jPos].freq;
653
690
  const rowCount = this.positions[jPos].rowCount;
654
691
  const alphabetSize = this.getAlphabetSize();
655
- if ((this.positionHeight == PositionHeight.Entropy) && (alphabetSize == null)) {
692
+ if ((this.positionHeight == PositionHeight.Entropy) && (alphabetSize == null))
656
693
  grok.shell.error('WebLogo: alphabet is undefined.');
657
- }
694
+
658
695
 
659
696
  const alphabetSizeLog = Math.log2(alphabetSize);
660
697
  const maxHeight = (this.positionHeight == PositionHeight.Entropy) ?
@@ -698,7 +735,8 @@ export class WebLogoViewer extends DG.JsViewer {
698
735
  }
699
736
  }
700
737
 
701
- if (!this.seqCol || !this.dataFrame || !this.cp || this.startPosition === -1 || this.endPosition === -1 || this.host == null || this.slider == null)
738
+ if (!this.seqCol || !this.dataFrame || !this.cp || this.startPosition === -1 ||
739
+ this.endPosition === -1 || this.host == null || this.slider == null)
702
740
  return;
703
741
 
704
742
  const g = this.canvas.getContext('2d');
@@ -734,7 +772,8 @@ export class WebLogoViewer extends DG.JsViewer {
734
772
  g.resetTransform();
735
773
  g.setTransform(
736
774
  hScale, 0, 0, 1,
737
- jPos * this.positionWidthWithMargin + this._positionWidth / 2 - this.positionWidthWithMargin * firstVisibleIndex, 0);
775
+ jPos * this.positionWidthWithMargin + this._positionWidth / 2 -
776
+ this.positionWidthWithMargin * firstVisibleIndex, 0);
738
777
  g.fillText(pos.name, 0, 0);
739
778
  }
740
779
  //#endregion Plot positionNames
@@ -813,34 +852,34 @@ export class WebLogoViewer extends DG.JsViewer {
813
852
  // vertical alignment
814
853
  let hostTopMargin = 0;
815
854
  switch (this.verticalAlignment) {
816
- case 'top':
817
- hostTopMargin = 0;
818
- break;
819
- case 'middle':
820
- hostTopMargin = Math.max(0, (this.root.clientHeight - height) / 2);
821
- break;
822
- case 'bottom':
823
- hostTopMargin = Math.max(0, this.root.clientHeight - height - sliderHeight);
824
- break;
855
+ case 'top':
856
+ hostTopMargin = 0;
857
+ break;
858
+ case 'middle':
859
+ hostTopMargin = Math.max(0, (this.root.clientHeight - height) / 2);
860
+ break;
861
+ case 'bottom':
862
+ hostTopMargin = Math.max(0, this.root.clientHeight - height - sliderHeight);
863
+ break;
825
864
  }
826
865
  // horizontal alignment
827
866
  let hostLeftMargin = 0;
828
867
  switch (this.horizontalAlignment) {
829
- case 'left':
830
- hostLeftMargin = 0;
831
- break;
832
- case 'center':
833
- hostLeftMargin = Math.max(0, (this.root.clientWidth - width) / 2);
834
- break;
835
- case 'right':
836
- hostLeftMargin = Math.max(0, this.root.clientWidth - width);
837
- break;
868
+ case 'left':
869
+ hostLeftMargin = 0;
870
+ break;
871
+ case 'center':
872
+ hostLeftMargin = Math.max(0, (this.root.clientWidth - width) / 2);
873
+ break;
874
+ case 'right':
875
+ hostLeftMargin = Math.max(0, this.root.clientWidth - width);
876
+ break;
838
877
  }
839
878
  this.host.style.setProperty('margin-top', `${hostTopMargin}px`, 'important');
840
879
  this.host.style.setProperty('margin-left', `${hostLeftMargin}px`, 'important');
841
- if (this.slider != null) {
880
+ if (this.slider != null)
842
881
  this.slider.root.style.setProperty('margin-top', `${hostTopMargin + canvasHeight}px`, 'important');
843
- }
882
+
844
883
 
845
884
  if (this.root.clientHeight <= height) {
846
885
  this.host.style.setProperty('height', `${this.root.clientHeight}px`);
@@ -857,7 +896,7 @@ export class WebLogoViewer extends DG.JsViewer {
857
896
 
858
897
  // -- Handle events --
859
898
 
860
- private sliderOnValuesChanged(value: any): void {
899
+ private sliderOnValuesChanged(_value: any): void {
861
900
  if ((this.host == null)) return;
862
901
 
863
902
  try {
@@ -874,30 +913,30 @@ export class WebLogoViewer extends DG.JsViewer {
874
913
  this.render(true);
875
914
  } catch (err: any) {
876
915
  const errMsg = errorToConsole(err);
877
- console.error('Bio: WebLogoViewer.sliderOnValuesChanged() error:\n' + errMsg);
916
+ _package.logger.error('Bio: WebLogoViewer.sliderOnValuesChanged() error:\n' + errMsg);
878
917
  //throw err; // Do not throw to prevent disabling event handler
879
918
  }
880
919
  }
881
920
 
882
- private dataFrameFilterOnChanged(value: any): void {
883
- console.debug('Bio: WebLogoViewer.dataFrameFilterChanged()');
921
+ private dataFrameFilterOnChanged(_value: any): void {
922
+ _package.logger.debug('Bio: WebLogoViewer.dataFrameFilterChanged()');
884
923
  try {
885
924
  this.updatePositions();
886
925
  this.render();
887
926
  } catch (err: any) {
888
927
  const errMsg = errorToConsole(err);
889
- console.error('Bio: WebLogoViewer.dataFrameFilterOnChanged() error:\n' + errMsg);
928
+ _package.logger.error('Bio: WebLogoViewer.dataFrameFilterOnChanged() error:\n' + errMsg);
890
929
  //throw err; // Do not throw to prevent disabling event handler
891
930
  }
892
931
  }
893
932
 
894
- private dataFrameSelectionOnChanged(value: any): void {
895
- console.debug('Bio: WebLogoViewer.dataFrameSelectionOnChanged()');
933
+ private dataFrameSelectionOnChanged(_value: any): void {
934
+ _package.logger.debug('Bio: WebLogoViewer.dataFrameSelectionOnChanged()');
896
935
  try {
897
936
  this.render();
898
937
  } catch (err: any) {
899
938
  const errMsg = errorToConsole(err);
900
- console.error('Bio: WebLogoViewer.dataFrameSelectionOnChanged() error:\n' + errMsg);
939
+ _package.logger.error('Bio: WebLogoViewer.dataFrameSelectionOnChanged() error:\n' + errMsg);
901
940
  //throw err; // Do not throw to prevent disabling event handler
902
941
  }
903
942
  }
@@ -916,10 +955,10 @@ export class WebLogoViewer extends DG.JsViewer {
916
955
  // const tooltipEl = ui.div([ui.div(`pos: ${jPos}`), preEl]);
917
956
  // ui.tooltip.show(tooltipEl, args.x + 16, args.y + 16);
918
957
  // } else
919
- if (this.dataFrame && this.seqCol && this.splitter && monomer) {
958
+ if (this.dataFrame && this.seqCol && monomer) {
920
959
  const atPI: PositionInfo = this.positions[jPos];
921
960
  const monomerAtPosSeqCount = countForMonomerAtPosition(
922
- this.dataFrame, this.seqCol, this.filter, this.splitter, monomer, atPI);
961
+ this.dataFrame, this.unitsHandler!, this.filter, monomer, atPI);
923
962
 
924
963
  const tooltipEl = ui.div([
925
964
  // ui.div(`pos ${jPos}`),
@@ -931,7 +970,7 @@ export class WebLogoViewer extends DG.JsViewer {
931
970
  }
932
971
  } catch (err: any) {
933
972
  const errMsg = errorToConsole(err);
934
- console.error('Bio: WebLogoViewer.canvasOnMouseMove() error:\n' + errMsg);
973
+ _package.logger.error('Bio: WebLogoViewer.canvasOnMouseMove() error:\n' + errMsg);
935
974
  //throw err; // Do not throw to prevent disabling event handler
936
975
  }
937
976
  }
@@ -943,7 +982,7 @@ export class WebLogoViewer extends DG.JsViewer {
943
982
  const [jPos, monomer] = this.getMonomer(this.canvas.getCursorPosition(args, r));
944
983
 
945
984
  // prevents deselect all rows if we miss monomer bounds
946
- if (this.dataFrame && this.seqCol && this.splitter && monomer) {
985
+ if (this.dataFrame && this.seqCol && this.unitsHandler && monomer) {
947
986
  const atPI: PositionInfo = this.positions[jPos];
948
987
 
949
988
  // this.dataFrame.selection.init((rowI: number) => {
@@ -952,14 +991,13 @@ export class WebLogoViewer extends DG.JsViewer {
952
991
  // });
953
992
  // Calculate a new BitSet object for selection to prevent interfering with existing
954
993
  const selBS: DG.BitSet = DG.BitSet.create(this.dataFrame.selection.length, (rowI: number) => {
955
- return checkSeqForMonomerAtPos(
956
- this.dataFrame, this.seqCol!, this.filter, rowI, this.splitter!, monomer, atPI);
994
+ return checkSeqForMonomerAtPos(this.dataFrame, this.unitsHandler!, this.filter, rowI, monomer, atPI);
957
995
  });
958
996
  this.dataFrame.selection.init((i) => selBS.get(i));
959
997
  }
960
998
  } catch (err: any) {
961
999
  const errMsg = errorToConsole(err);
962
- console.error('Bio: WebLogoViewer.canvasOnMouseDown() error:\n' + errMsg);
1000
+ _package.logger.error('Bio: WebLogoViewer.canvasOnMouseDown() error:\n' + errMsg);
963
1001
  //throw err; // Do not throw to prevent disabling event handler
964
1002
  }
965
1003
  }
@@ -972,34 +1010,31 @@ export class WebLogoViewer extends DG.JsViewer {
972
1010
  this.slider.scrollBy(this.slider.min + countOfScrollPositions);
973
1011
  } catch (err: any) {
974
1012
  const errMsg = errorToConsole(err);
975
- console.error('Bio: WebLogoViewer.canvasOnWheel() error:\n' + errMsg);
1013
+ _package.logger.error('Bio: WebLogoViewer.canvasOnWheel() error:\n' + errMsg);
976
1014
  //throw err; // Do not throw to prevent disabling event handler
977
1015
  }
978
1016
  }
979
1017
  }
980
1018
 
981
1019
  export function checkSeqForMonomerAtPos(
982
- df: DG.DataFrame, seqCol: DG.Column, filter: DG.BitSet, rowI: number,
983
- splitter: SplitterFunc, monomer: string, at: PositionInfo
1020
+ df: DG.DataFrame, unitsHandler: UnitsHandler, filter: DG.BitSet, rowI: number, monomer: string, at: PositionInfo,
984
1021
  ): boolean {
985
1022
  // if (!filter.get(rowI)) return false;
986
1023
  // TODO: Use BitSet.get(idx)
987
1024
  if (!filter.getSelectedIndexes().includes(rowI)) return false;
988
1025
 
989
- const seq = seqCol!.get(rowI);
990
- const seqM = seq ? splitter!(seq)[at.pos] : null;
1026
+ const seqMList: string[] = unitsHandler.splitted[rowI];
1027
+ const seqM = at.pos < seqMList.length ? seqMList[at.pos] : null;
991
1028
  return ((seqM === monomer) || (seqM === '' && monomer === '-'));
992
1029
  }
993
1030
 
994
1031
  export function countForMonomerAtPosition(
995
- df: DG.DataFrame, seqCol: DG.Column, filter: DG.BitSet,
996
- splitter: SplitterFunc, monomer: string, at: PositionInfo
1032
+ df: DG.DataFrame, uh: UnitsHandler, filter: DG.BitSet, monomer: string, at: PositionInfo
997
1033
  ): number {
998
1034
  const posMList: (string | null)[] = wu.count(0).take(df.rowCount)
999
1035
  .filter((rowI) => filter.get(rowI))
1000
1036
  .map((rowI) => {
1001
- const seq: string | null = seqCol!.get(rowI);
1002
- const seqMList: string[] = seq ? splitter!(seq) : [];
1037
+ const seqMList: string[] = uh.splitted[rowI];
1003
1038
  const seqMPos: number = at.pos;
1004
1039
  const seqM: string | null = seqMPos < seqMList.length ? seqMList[seqMPos] : null;
1005
1040
  return seqM;
@@ -1007,6 +1042,6 @@ export function countForMonomerAtPosition(
1007
1042
  // wu.count().take(this.dataFrame.rowCount).filter(function(iRow) {
1008
1043
  // return correctMonomerFilter(iRow, monomer, jPos);
1009
1044
  // }).reduce<number>((count, iRow) => count + 1, 0);
1010
- const monomerAtPosRowCount = posMList.filter((m) => m == monomer).reduce((count, m) => count + 1, 0);
1045
+ const monomerAtPosRowCount = posMList.filter((m) => m == monomer).reduce((count, _m) => count + 1, 0);
1011
1046
  return monomerAtPosRowCount;
1012
1047
  }