@datagrok/bio 2.11.21 → 2.11.23
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/CHANGELOG.md +2 -0
- package/detectors.js +0 -13
- package/dist/356.js +1 -1
- package/dist/356.js.map +1 -1
- package/dist/796.js +1 -1
- package/dist/796.js.map +1 -1
- 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/package.json +2 -1
- package/src/demo/bio01a-hierarchical-clustering-and-sequence-space.ts +6 -10
- package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +7 -9
- package/src/utils/macromolecule-column-widget.ts +6 -1
- package/src/viewers/web-logo-viewer.ts +41 -38
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.11.
|
|
8
|
+
"version": "2.11.23",
|
|
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",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@datagrok-libraries/ml": "^6.3.68",
|
|
40
40
|
"@datagrok-libraries/tutorials": "^1.3.11",
|
|
41
41
|
"@datagrok-libraries/utils": "^4.1.36",
|
|
42
|
+
"@datagrok-libraries/math": "^1.0.7",
|
|
42
43
|
"cash-dom": "^8.0.0",
|
|
43
44
|
"css-loader": "^6.7.3",
|
|
44
45
|
"datagrok-api": "^1.16.0",
|
|
@@ -3,13 +3,11 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import {_package} from '../package';
|
|
6
|
-
|
|
7
|
-
import * as lev from 'fastest-levenshtein';
|
|
8
|
-
import {DistanceMatrix} from '@datagrok-libraries/ml/src/distance-matrix';
|
|
9
6
|
import {getTreeHelper, ITreeHelper} from '@datagrok-libraries/bio/src/trees/tree-helper';
|
|
10
7
|
import {getDendrogramService, IDendrogramService} from '@datagrok-libraries/bio/src/trees/dendrogram';
|
|
11
8
|
import {demoSequenceSpace, handleError} from './utils';
|
|
12
9
|
import {DemoScript} from '@datagrok-libraries/tutorials/src/demo-script';
|
|
10
|
+
import {getClusterMatrixWorker} from '@datagrok-libraries/math';
|
|
13
11
|
|
|
14
12
|
const dataFn = 'data/sample_FASTA_PT_activity.csv';
|
|
15
13
|
const seqColName = 'sequence';
|
|
@@ -55,13 +53,11 @@ export async function demoBio01aUI() {
|
|
|
55
53
|
delay: 2000,
|
|
56
54
|
})
|
|
57
55
|
.step('Cluster sequences', async () => {
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
const treeRoot = await treeHelper.hierarchicalClusteringByDistance(distance, 'ward');
|
|
56
|
+
const distance = await treeHelper.calcDistanceMatrix(df, [seqColName]);
|
|
57
|
+
const clusterMatrix = await getClusterMatrixWorker(
|
|
58
|
+
distance!.data, df.rowCount, 1,
|
|
59
|
+
);
|
|
60
|
+
const treeRoot = treeHelper.parseClusterMatrix(clusterMatrix);
|
|
65
61
|
dendrogramSvc.injectTreeForGrid(view.grid, treeRoot, undefined, 150, undefined);
|
|
66
62
|
}, {
|
|
67
63
|
description: `Perform hierarchical clustering to reveal relationships between sequences.`,
|
|
@@ -6,14 +6,13 @@ import {_package, activityCliffs} from '../package';
|
|
|
6
6
|
import $ from 'cash-dom';
|
|
7
7
|
|
|
8
8
|
import {TEMPS as acTEMPS} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
|
|
9
|
-
import * as lev from 'fastest-levenshtein';
|
|
10
|
-
import {DistanceMatrix} from '@datagrok-libraries/ml/src/distance-matrix';
|
|
11
9
|
import {getTreeHelper, ITreeHelper} from '@datagrok-libraries/bio/src/trees/tree-helper';
|
|
12
10
|
import {getDendrogramService, IDendrogramService} from '@datagrok-libraries/bio/src/trees/dendrogram';
|
|
13
11
|
import {handleError} from './utils';
|
|
14
12
|
import {DemoScript} from '@datagrok-libraries/tutorials/src/demo-script';
|
|
15
13
|
import {DimReductionMethods} from '@datagrok-libraries/ml/src/reduce-dimensionality';
|
|
16
14
|
import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule-distance-functions';
|
|
15
|
+
import {getClusterMatrixWorker} from '@datagrok-libraries/math';
|
|
17
16
|
|
|
18
17
|
const dataFn: string = 'data/sample_FASTA_PT_activity.csv';
|
|
19
18
|
|
|
@@ -67,13 +66,12 @@ export async function demoBio01bUI() {
|
|
|
67
66
|
})
|
|
68
67
|
.step('Cluster sequences', async () => {
|
|
69
68
|
const progressBar = DG.TaskBarProgressIndicator.create(`Running sequence clustering...`);
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const treeRoot = await treeHelper.hierarchicalClusteringByDistance(distance, 'ward');
|
|
69
|
+
|
|
70
|
+
const distance = await treeHelper.calcDistanceMatrix(df, ['sequence']);
|
|
71
|
+
const clusterMatrix = await getClusterMatrixWorker(
|
|
72
|
+
distance!.data, df.rowCount, 1,
|
|
73
|
+
);
|
|
74
|
+
const treeRoot = treeHelper.parseClusterMatrix(clusterMatrix);
|
|
77
75
|
progressBar.close();
|
|
78
76
|
dendrogramSvc.injectTreeForGrid(view.grid, treeRoot, undefined, 150, undefined);
|
|
79
77
|
|
|
@@ -12,7 +12,7 @@ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
|
12
12
|
export class MacromoleculeColumnWidget extends DG.Widget {
|
|
13
13
|
private viewed: boolean = false;
|
|
14
14
|
|
|
15
|
-
private seqCol: DG.Column<string>;
|
|
15
|
+
private readonly seqCol: DG.Column<string>;
|
|
16
16
|
|
|
17
17
|
private wlViewer: WebLogoViewer;
|
|
18
18
|
|
|
@@ -44,4 +44,9 @@ export class MacromoleculeColumnWidget extends DG.Widget {
|
|
|
44
44
|
this.root.style.width = '100%';
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
override detach() {
|
|
49
|
+
this.wlViewer.detach();
|
|
50
|
+
super.detach();
|
|
51
|
+
}
|
|
47
52
|
}
|
|
@@ -2,6 +2,7 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import $ from 'cash-dom';
|
|
5
6
|
import wu from 'wu';
|
|
6
7
|
import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
|
|
7
8
|
|
|
@@ -293,6 +294,10 @@ enum WlRenderLevel {
|
|
|
293
294
|
Freqs = 2,
|
|
294
295
|
}
|
|
295
296
|
|
|
297
|
+
export const Debounces = new class {
|
|
298
|
+
render: number = 20;
|
|
299
|
+
}();
|
|
300
|
+
|
|
296
301
|
const POSITION_LABELS_HEIGHT: number = 12;
|
|
297
302
|
|
|
298
303
|
export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
@@ -506,7 +511,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
506
511
|
const dataFrameTxt: string = this.dataFrame ? 'data' : 'null';
|
|
507
512
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.buildView( dataFrame = ${dataFrameTxt} ) start`);
|
|
508
513
|
const dpr = window.devicePixelRatio;
|
|
509
|
-
this.viewSubs.push(DG.debounce(this.renderRequest)
|
|
514
|
+
this.viewSubs.push(DG.debounce(this.renderRequest, Debounces.render)
|
|
510
515
|
.subscribe(this.renderRequestOnDebounce.bind(this)));
|
|
511
516
|
|
|
512
517
|
this.helpUrl = '/help/visualize/viewers/web-logo.md';
|
|
@@ -558,7 +563,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
558
563
|
this.viewSubs.push(
|
|
559
564
|
fromEvent<WheelEvent>(this.canvas, 'wheel').subscribe(this.canvasOnWheel.bind(this)));
|
|
560
565
|
|
|
561
|
-
|
|
566
|
+
this.render(WlRenderLevel.Freqs, 'buildView');
|
|
562
567
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.buildView() end`);
|
|
563
568
|
}
|
|
564
569
|
|
|
@@ -589,7 +594,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
589
594
|
this.unitsHandler = UnitsHandler.getOrCreate(this.seqCol);
|
|
590
595
|
|
|
591
596
|
this.palette = pickUpPalette(this.seqCol);
|
|
592
|
-
this.
|
|
597
|
+
this.render(WlRenderLevel.Freqs, 'updateSeqCol()');
|
|
593
598
|
this.error = null;
|
|
594
599
|
} catch (err: any) {
|
|
595
600
|
this.seqCol = null;
|
|
@@ -608,36 +613,6 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
608
613
|
}
|
|
609
614
|
}
|
|
610
615
|
|
|
611
|
-
/** Updates {@link positionNames} and calculates {@link startPosition} and {@link endPosition}.
|
|
612
|
-
* Calls {@link render}() with {@link WlRenderLevel.Freqs}
|
|
613
|
-
*/
|
|
614
|
-
private updatePositions(): void {
|
|
615
|
-
if (!this.seqCol) return;
|
|
616
|
-
|
|
617
|
-
const dfFilter = this.getFilter();
|
|
618
|
-
const maxLength: number = dfFilter.trueCount === 0 ? this.unitsHandler!.maxLength :
|
|
619
|
-
wu.enumerate(this.unitsHandler!.splitted).map(([mList, rowI]) => {
|
|
620
|
-
return dfFilter.get(rowI) && !!mList ? mList.length : 0;
|
|
621
|
-
}).reduce((max, l) => Math.max(max, l), 0);
|
|
622
|
-
|
|
623
|
-
/** positionNames and positionLabel can be set up through the column's tags only */
|
|
624
|
-
const positionNamesTxt = this.seqCol.getTag(bioTAGS.positionNames);
|
|
625
|
-
const positionLabelsTxt = this.seqCol.getTag(bioTAGS.positionLabels);
|
|
626
|
-
this.positionNames = !!positionNamesTxt ? positionNamesTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
627
|
-
[...Array(maxLength).keys()].map((jPos) => `${jPos + 1}`)/* fallback if tag is not provided */;
|
|
628
|
-
this.positionLabels = !!positionLabelsTxt ? positionLabelsTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
629
|
-
undefined;
|
|
630
|
-
|
|
631
|
-
this.startPosition = (this.startPositionName && this.positionNames &&
|
|
632
|
-
this.positionNames.includes(this.startPositionName)) ?
|
|
633
|
-
this.positionNames.indexOf(this.startPositionName) : 0;
|
|
634
|
-
this.endPosition = (this.endPositionName && this.positionNames &&
|
|
635
|
-
this.positionNames.includes(this.endPositionName)) ?
|
|
636
|
-
this.positionNames.indexOf(this.endPositionName) : (maxLength - 1);
|
|
637
|
-
|
|
638
|
-
this.render(WlRenderLevel.Freqs, 'updatePositions');
|
|
639
|
-
}
|
|
640
|
-
|
|
641
616
|
private getFilter(): DG.BitSet {
|
|
642
617
|
let dfFilterRes: DG.BitSet;
|
|
643
618
|
switch (this.filterSource) {
|
|
@@ -851,13 +826,13 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
851
826
|
case PROPS.shrinkEmptyTail:
|
|
852
827
|
case PROPS.skipEmptyPositions:
|
|
853
828
|
case PROPS.positionHeight: {
|
|
854
|
-
this.
|
|
829
|
+
this.render(WlRenderLevel.Freqs, `onPropertyChanged( ${property.name} )`);
|
|
855
830
|
break;
|
|
856
831
|
}
|
|
857
832
|
|
|
858
833
|
case PROPS.valueColumnName:
|
|
859
834
|
case PROPS.valueAggrType: {
|
|
860
|
-
this.render(WlRenderLevel.Freqs, `onPropertyChanged(${property.name})`);
|
|
835
|
+
this.render(WlRenderLevel.Freqs, `onPropertyChanged( ${property.name} )`);
|
|
861
836
|
break;
|
|
862
837
|
}
|
|
863
838
|
// this.positionWidth obtains a new value
|
|
@@ -892,7 +867,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
892
867
|
}
|
|
893
868
|
|
|
894
869
|
/** Remove all handlers when table is a detach */
|
|
895
|
-
public override
|
|
870
|
+
public override detach() {
|
|
896
871
|
const logPrefix = `${this.viewerToLog()}.detach()`;
|
|
897
872
|
_package.logger.debug(`${logPrefix}, in`);
|
|
898
873
|
|
|
@@ -984,6 +959,31 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
984
959
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.render.calculateFreqsInt(), start `);
|
|
985
960
|
if (!this.host || !this.seqCol || !this.dataFrame) return;
|
|
986
961
|
|
|
962
|
+
// region updatePositions
|
|
963
|
+
|
|
964
|
+
const dfFilter = this.getFilter();
|
|
965
|
+
const maxLength: number = dfFilter.trueCount === 0 ? this.unitsHandler!.maxLength :
|
|
966
|
+
wu.enumerate(this.unitsHandler!.splitted).map(([mList, rowI]) => {
|
|
967
|
+
return dfFilter.get(rowI) && !!mList ? mList.length : 0;
|
|
968
|
+
}).reduce((max, l) => Math.max(max, l), 0);
|
|
969
|
+
|
|
970
|
+
/** positionNames and positionLabel can be set up through the column's tags only */
|
|
971
|
+
const positionNamesTxt = this.seqCol.getTag(bioTAGS.positionNames);
|
|
972
|
+
const positionLabelsTxt = this.seqCol.getTag(bioTAGS.positionLabels);
|
|
973
|
+
this.positionNames = !!positionNamesTxt ? positionNamesTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
974
|
+
[...Array(maxLength).keys()].map((jPos) => `${jPos + 1}`)/* fallback if tag is not provided */;
|
|
975
|
+
this.positionLabels = !!positionLabelsTxt ? positionLabelsTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
976
|
+
undefined;
|
|
977
|
+
|
|
978
|
+
this.startPosition = (this.startPositionName && this.positionNames &&
|
|
979
|
+
this.positionNames.includes(this.startPositionName)) ?
|
|
980
|
+
this.positionNames.indexOf(this.startPositionName) : 0;
|
|
981
|
+
this.endPosition = (this.endPositionName && this.positionNames &&
|
|
982
|
+
this.positionNames.includes(this.endPositionName)) ?
|
|
983
|
+
this.positionNames.indexOf(this.endPositionName) : (maxLength - 1);
|
|
984
|
+
|
|
985
|
+
// endregion updatePositions
|
|
986
|
+
|
|
987
987
|
const length: number = this.startPosition <= this.endPosition ? this.endPosition - this.startPosition + 1 : 0;
|
|
988
988
|
this.unitsHandler = UnitsHandler.getOrCreate(this.seqCol);
|
|
989
989
|
const posCount: number = this.startPosition <= this.endPosition ? this.endPosition - this.startPosition + 1 : 0;
|
|
@@ -996,7 +996,6 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
996
996
|
}
|
|
997
997
|
|
|
998
998
|
// 2022-05-05 askalkin instructed to show WebLogo based on filter (not selection)
|
|
999
|
-
const dfFilter = this.getFilter();
|
|
1000
999
|
const dfRowCount = this.dataFrame.rowCount;
|
|
1001
1000
|
const splitted = this.unitsHandler.splitted;
|
|
1002
1001
|
|
|
@@ -1136,6 +1135,11 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1136
1135
|
}
|
|
1137
1136
|
|
|
1138
1137
|
private renderRequestOnDebounce(renderLevel: WlRenderLevel): void {
|
|
1138
|
+
const logPrefix = `${this.viewerToLog()}.renderRequestOnDebounce()`;
|
|
1139
|
+
if ($(this.root).offsetParent().get()[0]?.tagName === 'HTML') {
|
|
1140
|
+
_package.logger.warning(`${logPrefix}, $(this.root).offsetParent() is the 'HTML' tag.`);
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1139
1143
|
this.requestedRenderLevel = WlRenderLevel.None;
|
|
1140
1144
|
this.renderInt(renderLevel)
|
|
1141
1145
|
.catch((err: any) => {
|
|
@@ -1176,7 +1180,6 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1176
1180
|
private dataFrameFilterOnChanged(_value: any): void {
|
|
1177
1181
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.dataFrameFilterChanged()`);
|
|
1178
1182
|
try {
|
|
1179
|
-
this.updatePositions();
|
|
1180
1183
|
if (this.filterSource === FilterSources.Filtered)
|
|
1181
1184
|
this.render(WlRenderLevel.Freqs, 'dataFrameFilterOnChanged');
|
|
1182
1185
|
} catch (err: any) {
|