@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.
- package/.eslintrc.json +6 -8
- package/README.md +22 -7
- package/detectors.js +21 -12
- package/dist/1.js +2 -0
- package/dist/1.js.map +1 -0
- package/dist/18.js +2 -0
- package/dist/18.js.map +1 -0
- package/dist/190.js +2 -0
- package/dist/190.js.map +1 -0
- package/dist/452.js +2 -0
- package/dist/452.js.map +1 -0
- package/dist/729.js +2 -0
- package/dist/729.js.map +1 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/libraries/broken-lib.sdf +136 -0
- package/files/libraries/group1/mock-lib-3.json +74 -0
- package/files/libraries/mock-lib-2.json +48 -0
- package/files/tests/100_3_clustests.csv +100 -0
- package/files/tests/100_3_clustests_empty_vals.csv +100 -0
- package/files/tests/peptides_motif-with-random_10000.csv +9998 -0
- package/package.json +4 -4
- package/scripts/sequence_generator.py +164 -48
- package/src/analysis/sequence-activity-cliffs.ts +7 -9
- package/src/analysis/sequence-diversity-viewer.ts +8 -3
- package/src/analysis/sequence-search-base-viewer.ts +4 -3
- package/src/analysis/sequence-similarity-viewer.ts +13 -7
- package/src/analysis/sequence-space.ts +15 -12
- package/src/analysis/workers/mm-distance-array-service.ts +48 -0
- package/src/analysis/workers/mm-distance-array-worker.ts +29 -0
- package/src/analysis/workers/mm-distance-worker-creator.ts +6 -9
- package/src/apps/web-logo-app.ts +34 -0
- package/src/calculations/monomerLevelMols.ts +10 -12
- package/src/demo/bio01-similarity-diversity.ts +4 -5
- package/src/demo/bio01a-hierarchical-clustering-and-sequence-space.ts +6 -7
- package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +7 -8
- package/src/demo/bio03-atomic-level.ts +1 -4
- package/src/demo/bio05-helm-msa-sequence-space.ts +6 -4
- package/src/demo/utils.ts +3 -4
- package/src/package-test.ts +1 -2
- package/src/package.ts +135 -82
- package/src/seq_align.ts +482 -483
- package/src/substructure-search/substructure-search.ts +3 -3
- package/src/tests/Palettes-test.ts +1 -1
- package/src/tests/WebLogo-positions-test.ts +12 -35
- package/src/tests/_first-tests.ts +1 -1
- package/src/tests/activity-cliffs-tests.ts +10 -7
- package/src/tests/activity-cliffs-utils.ts +6 -5
- package/src/tests/bio-tests.ts +20 -25
- package/src/tests/checkInputColumn-tests.ts +5 -11
- package/src/tests/converters-test.ts +19 -37
- package/src/tests/detectors-benchmark-tests.ts +35 -37
- package/src/tests/detectors-tests.ts +29 -34
- package/src/tests/detectors-weak-and-likely-tests.ts +11 -21
- package/src/tests/fasta-export-tests.ts +3 -3
- package/src/tests/fasta-handler-test.ts +2 -3
- package/src/tests/lib-tests.ts +2 -4
- package/src/tests/mm-distance-tests.ts +25 -17
- package/src/tests/monomer-libraries-tests.ts +1 -1
- package/src/tests/msa-tests.ts +12 -9
- package/src/tests/pepsea-tests.ts +6 -3
- package/src/tests/renderers-test.ts +13 -11
- package/src/tests/sequence-space-test.ts +10 -8
- package/src/tests/sequence-space-utils.ts +6 -4
- package/src/tests/similarity-diversity-tests.ts +47 -61
- package/src/tests/splitters-test.ts +14 -20
- package/src/tests/to-atomic-level-tests.ts +9 -17
- package/src/tests/units-handler-splitted-tests.ts +106 -0
- package/src/tests/units-handler-tests.ts +22 -26
- package/src/tests/utils/sequences-generators.ts +6 -2
- package/src/tests/utils.ts +10 -4
- package/src/tests/viewers.ts +1 -1
- package/src/utils/atomic-works.ts +49 -57
- package/src/utils/cell-renderer.ts +25 -8
- package/src/utils/check-input-column.ts +19 -4
- package/src/utils/constants.ts +3 -3
- package/src/utils/convert.ts +56 -23
- package/src/utils/monomer-lib.ts +83 -64
- package/src/utils/multiple-sequence-alignment-ui.ts +24 -21
- package/src/utils/multiple-sequence-alignment.ts +2 -2
- package/src/utils/pepsea.ts +17 -7
- package/src/utils/save-as-fasta.ts +11 -4
- package/src/utils/ui-utils.ts +1 -1
- package/src/viewers/vd-regions-viewer.ts +21 -22
- package/src/viewers/web-logo-viewer.ts +189 -154
- package/src/widgets/bio-substructure-filter.ts +9 -6
- package/src/widgets/representations.ts +11 -12
- package/tsconfig.json +1 -1
- package/dist/258.js +0 -2
- package/dist/258.js.map +0 -1
- package/dist/457.js +0 -2
- package/dist/457.js.map +0 -1
- package/dist/562.js +0 -2
- package/dist/562.js.map +0 -1
- package/dist/925.js +0 -2
- package/dist/925.js.map +0 -1
- 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,
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
this.
|
|
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(...
|
|
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) ||
|
|
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
|
-
|
|
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) +
|
|
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
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
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
|
-
|
|
569
|
+
_package.logger.debug('Bio: WebLogoViewer.onTableAttached(), ');
|
|
512
570
|
|
|
513
|
-
|
|
514
|
-
console.debug(`Bio: WebLogoViewer<${this.viewerId}>.onTableAttached( dataFrame = ${dataFrameTxt} ) start`);
|
|
571
|
+
// -- Props editors --
|
|
515
572
|
|
|
516
|
-
|
|
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
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
616
|
-
|
|
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 ||
|
|
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 -
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
883
|
-
|
|
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
|
-
|
|
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(
|
|
895
|
-
|
|
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
|
-
|
|
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 &&
|
|
958
|
+
if (this.dataFrame && this.seqCol && monomer) {
|
|
920
959
|
const atPI: PositionInfo = this.positions[jPos];
|
|
921
960
|
const monomerAtPosSeqCount = countForMonomerAtPosition(
|
|
922
|
-
this.dataFrame, this.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
990
|
-
const seqM =
|
|
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,
|
|
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
|
|
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,
|
|
1045
|
+
const monomerAtPosRowCount = posMList.filter((m) => m == monomer).reduce((count, _m) => count + 1, 0);
|
|
1011
1046
|
return monomerAtPosRowCount;
|
|
1012
1047
|
}
|