@datagrok/peptides 0.3.0 → 0.4.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.
- package/.eslintrc.json +29 -0
- package/package.json +3 -3
- package/src/describe.ts +77 -19
- package/src/package.ts +1 -1
- package/src/peptides.ts +74 -0
- package/src/utils/cell-renderer.ts +63 -45
- package/src/utils/chem-palette.ts +13 -13
- package/src/utils/correlation-analysis.ts +37 -20
- package/src/utils/peptide-similarity-space.ts +11 -4
- package/src/utils/split-aligned.ts +1 -1
- package/src/viewers/model.ts +29 -16
- package/src/viewers/sar-viewer.ts +14 -8
- package/src/viewers/stacked-barchart-viewer.ts +2 -2
- package/src/widgets/analyze-peptides.ts +6 -32
- package/src/widgets/manual-alignment.ts +5 -4
- package/src/widgets/peptide-molecule.ts +1 -1
- package/src/workers/dimensionality-reducer.ts +1 -1
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"extends": [
|
|
7
|
+
"google"
|
|
8
|
+
],
|
|
9
|
+
"parser": "@typescript-eslint/parser",
|
|
10
|
+
"parserOptions": {
|
|
11
|
+
"ecmaVersion": 12,
|
|
12
|
+
"sourceType": "module"
|
|
13
|
+
},
|
|
14
|
+
"plugins": [
|
|
15
|
+
"@typescript-eslint"
|
|
16
|
+
],
|
|
17
|
+
"rules": {
|
|
18
|
+
"indent": [
|
|
19
|
+
"error",
|
|
20
|
+
2
|
|
21
|
+
],
|
|
22
|
+
"max-len": [
|
|
23
|
+
"error",
|
|
24
|
+
120
|
|
25
|
+
],
|
|
26
|
+
"spaced-comment": "off",
|
|
27
|
+
"require-jsdoc": "off"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@keckelt/tsne": "^1.0.2",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"logojs-react": "^2.1.1",
|
|
14
14
|
"rxjs": "^6.5.5",
|
|
15
15
|
"umap-js": "^1.3.3",
|
|
16
|
-
"@datagrok-libraries/utils": ">=0.0.
|
|
17
|
-
"@datagrok-libraries/statistics": ">=0.1.
|
|
16
|
+
"@datagrok-libraries/utils": ">=0.0.11",
|
|
17
|
+
"@datagrok-libraries/statistics": ">=0.1.5",
|
|
18
18
|
"@types/d3": "^7.0.0",
|
|
19
19
|
"@types/jquery": "^3.5.6"
|
|
20
20
|
},
|
package/src/describe.ts
CHANGED
|
@@ -4,12 +4,49 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
import {splitAlignedPeptides} from './utils/split-aligned';
|
|
6
6
|
import {tTest} from '@datagrok-libraries/statistics/src/tests';
|
|
7
|
-
import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests
|
|
7
|
+
import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests';
|
|
8
8
|
import {ChemPalette} from './utils/chem-palette';
|
|
9
9
|
import {setAARRenderer} from './utils/cell-renderer';
|
|
10
10
|
|
|
11
11
|
const cp = new ChemPalette('grok');
|
|
12
12
|
|
|
13
|
+
const aarGroups = {
|
|
14
|
+
'R': 'PC',
|
|
15
|
+
'H': 'PC',
|
|
16
|
+
'K': 'PC',
|
|
17
|
+
'D': 'NC',
|
|
18
|
+
'E': 'NC',
|
|
19
|
+
'S': 'U',
|
|
20
|
+
'T': 'U',
|
|
21
|
+
'N': 'U',
|
|
22
|
+
'Q': 'U',
|
|
23
|
+
'C': 'SC',
|
|
24
|
+
'U': 'SC',
|
|
25
|
+
'G': 'SC',
|
|
26
|
+
'P': 'SC',
|
|
27
|
+
'A': 'H',
|
|
28
|
+
'V': 'H',
|
|
29
|
+
'I': 'H',
|
|
30
|
+
'L': 'H',
|
|
31
|
+
'M': 'H',
|
|
32
|
+
'F': 'H',
|
|
33
|
+
'Y': 'H',
|
|
34
|
+
'W': 'H',
|
|
35
|
+
'-': '-',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const groupDescription: {[key: string]: {'description': string, 'aminoAcids': string[]}} = {
|
|
39
|
+
'PC': {'description': 'Positive Amino Acids, with Electrically Charged Side Chains', 'aminoAcids': ['R', 'H', 'K']},
|
|
40
|
+
'NC': {'description': 'Negative Amino Acids, with Electrically Charged Side Chains', 'aminoAcids': ['D', 'E']},
|
|
41
|
+
'U': {'description': 'Amino Acids with Polar Uncharged Side Chains', 'aminoAcids': ['S', 'T', 'N', 'Q']},
|
|
42
|
+
'SC': {'description': 'Special Cases', 'aminoAcids': ['C', 'U', 'G', 'P']},
|
|
43
|
+
'H': {
|
|
44
|
+
'description': 'Amino Acids with Hydrophobic Side Chain',
|
|
45
|
+
'aminoAcids': ['A', 'V', 'I', 'L', 'M', 'F', 'Y', 'W'],
|
|
46
|
+
},
|
|
47
|
+
'-': {'description': 'Unknown Amino Acid', 'aminoAcids': ['-']},
|
|
48
|
+
};
|
|
49
|
+
|
|
13
50
|
export async function describe(
|
|
14
51
|
df: DG.DataFrame,
|
|
15
52
|
activityColumn: string,
|
|
@@ -17,7 +54,8 @@ export async function describe(
|
|
|
17
54
|
sourceGrid: DG.Grid,
|
|
18
55
|
twoColorMode: boolean,
|
|
19
56
|
initialBitset: DG.BitSet | null,
|
|
20
|
-
|
|
57
|
+
grouping: boolean,
|
|
58
|
+
): Promise<[DG.Grid, DG.Grid, DG.DataFrame, {[key: string]: string}]> {
|
|
21
59
|
//Split the aligned sequence into separate AARs
|
|
22
60
|
let splitSeqDf: DG.DataFrame | undefined;
|
|
23
61
|
let invalidIndexes: number[];
|
|
@@ -50,6 +88,7 @@ export async function describe(
|
|
|
50
88
|
setAARRenderer(col, sourceGrid);
|
|
51
89
|
}
|
|
52
90
|
}
|
|
91
|
+
|
|
53
92
|
if (sourceGrid) {
|
|
54
93
|
const colNames:string[] = [];
|
|
55
94
|
for (let i = 0; i < sourceGrid.columns.length; i++) {
|
|
@@ -105,6 +144,17 @@ export async function describe(
|
|
|
105
144
|
|
|
106
145
|
let matrixDf = splitSeqDf.unpivot([activityColumnScaled], positionColumns, positionColName, aminoAcidResidue);
|
|
107
146
|
|
|
147
|
+
//TODO: move to chem palette
|
|
148
|
+
let groupMapping: {[key: string]: string} = {};
|
|
149
|
+
if (grouping) {
|
|
150
|
+
groupMapping = aarGroups;
|
|
151
|
+
const aarCol = matrixDf.getCol(aminoAcidResidue);
|
|
152
|
+
aarCol.init((index) => groupMapping[aarCol.get(index)[0]] ?? '-');
|
|
153
|
+
aarCol.compact();
|
|
154
|
+
} else {
|
|
155
|
+
Object.keys(aarGroups).forEach((value) => groupMapping[value] = value);
|
|
156
|
+
}
|
|
157
|
+
|
|
108
158
|
//statistics for specific AAR at a specific position
|
|
109
159
|
matrixDf = matrixDf.groupBy([positionColName, aminoAcidResidue])
|
|
110
160
|
.add('count', activityColumnScaled, 'Count')
|
|
@@ -135,14 +185,14 @@ export async function describe(
|
|
|
135
185
|
AAR = matrixDf.get(aminoAcidResidue, i);
|
|
136
186
|
|
|
137
187
|
//@ts-ignore
|
|
138
|
-
splitSeqDf.rows.select((row) => row[position] === AAR);
|
|
188
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] === AAR);
|
|
139
189
|
currentActivity = splitSeqDf
|
|
140
190
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
141
191
|
.getCol(activityColumnScaled)
|
|
142
192
|
.toList();
|
|
143
193
|
|
|
144
194
|
//@ts-ignore
|
|
145
|
-
splitSeqDf.rows.select((row) => row[position] !== AAR);
|
|
195
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] !== AAR);
|
|
146
196
|
otherActivity = splitSeqDf
|
|
147
197
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
148
198
|
.getCol(activityColumnScaled)
|
|
@@ -224,17 +274,14 @@ export async function describe(
|
|
|
224
274
|
SARVgrid.col('pValue')!.format = 'four digits after comma';
|
|
225
275
|
SARVgrid.col('pValue')!.name = 'P-Value';
|
|
226
276
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
setAARRenderer(
|
|
231
|
-
break;
|
|
277
|
+
if (!grouping) {
|
|
278
|
+
let tempCol = matrixDf.columns.byName(aminoAcidResidue);
|
|
279
|
+
if (tempCol) {
|
|
280
|
+
setAARRenderer(tempCol, SARgrid);
|
|
232
281
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
setAARRenderer(col, SARVgrid);
|
|
237
|
-
break;
|
|
282
|
+
tempCol = sequenceDf.columns.byName(aminoAcidResidue);
|
|
283
|
+
if (tempCol) {
|
|
284
|
+
setAARRenderer(tempCol, SARgrid);
|
|
238
285
|
}
|
|
239
286
|
}
|
|
240
287
|
|
|
@@ -362,7 +409,13 @@ export async function describe(
|
|
|
362
409
|
cell.cell.value !== null &&
|
|
363
410
|
cell.tableRowIndex !== null
|
|
364
411
|
) {
|
|
365
|
-
|
|
412
|
+
if (grouping) {
|
|
413
|
+
const currentGroup = groupDescription[cell.cell.value];
|
|
414
|
+
const divText = ui.divText('Amino Acids in this group: ' + currentGroup['aminoAcids'].join(', '));
|
|
415
|
+
ui.tooltip.show(ui.divV([ui.h3(currentGroup['description']), divText]), x, y);
|
|
416
|
+
} else {
|
|
417
|
+
cp.showTooltip(cell, x, y);
|
|
418
|
+
}
|
|
366
419
|
}
|
|
367
420
|
return true;
|
|
368
421
|
};
|
|
@@ -376,9 +429,14 @@ export async function describe(
|
|
|
376
429
|
}
|
|
377
430
|
});
|
|
378
431
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
432
|
+
for (const col of matrixDf.columns.names()) {
|
|
433
|
+
SARgrid.col(col)!.width = SARgrid.props.rowHeight;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (grouping) {
|
|
437
|
+
SARgrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
438
|
+
SARVgrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
439
|
+
}
|
|
382
440
|
|
|
383
|
-
return [SARgrid, SARVgrid, statsDf];
|
|
441
|
+
return [SARgrid, SARVgrid, statsDf, groupMapping];
|
|
384
442
|
}
|
package/src/package.ts
CHANGED
|
@@ -197,7 +197,7 @@ export function manualAlignment(monomer: string) {
|
|
|
197
197
|
//input: column col {semType: alignedSequence}
|
|
198
198
|
//output: widget result
|
|
199
199
|
export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
|
|
200
|
-
const widget = new PeptideSimilaritySpaceWidget(col);
|
|
200
|
+
const widget = new PeptideSimilaritySpaceWidget(col, view ?? grok.shell.v);
|
|
201
201
|
return await widget.draw();
|
|
202
202
|
}
|
|
203
203
|
|
package/src/peptides.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as ui from 'datagrok-api/ui';
|
|
3
|
+
import * as DG from 'datagrok-api/dg';
|
|
4
|
+
import {createPeptideSimilaritySpaceViewer} from './utils/peptide-similarity-space';
|
|
5
|
+
import {addViewerToHeader} from './viewers/stacked-barchart-viewer';
|
|
6
|
+
|
|
7
|
+
export class Peptides {
|
|
8
|
+
async init(
|
|
9
|
+
tableGrid: DG.Grid,
|
|
10
|
+
view: DG.TableView,
|
|
11
|
+
currentDf: DG.DataFrame,
|
|
12
|
+
options: {[key: string]: string},
|
|
13
|
+
col: DG.Column,
|
|
14
|
+
activityColumnChoice: string
|
|
15
|
+
) {
|
|
16
|
+
for (let i = 0; i < tableGrid.columns.length; i++) {
|
|
17
|
+
const col = tableGrid.columns.byIndex(i);
|
|
18
|
+
if (col &&
|
|
19
|
+
col.name &&
|
|
20
|
+
col.column?.semType != 'aminoAcids'
|
|
21
|
+
) {
|
|
22
|
+
//@ts-ignore
|
|
23
|
+
tableGrid.columns.byIndex(i)?.visible = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
|
|
28
|
+
|
|
29
|
+
const sarViewer = view.addViewer('peptide-sar-viewer', options);
|
|
30
|
+
const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
|
|
31
|
+
|
|
32
|
+
const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
|
|
33
|
+
const sarVNode = view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
|
|
34
|
+
|
|
35
|
+
const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
|
|
36
|
+
currentDf,
|
|
37
|
+
col,
|
|
38
|
+
't-SNE',
|
|
39
|
+
'Levenshtein',
|
|
40
|
+
100,
|
|
41
|
+
view,
|
|
42
|
+
`${activityColumnChoice}Scaled`,
|
|
43
|
+
);
|
|
44
|
+
const psNode = view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
|
|
45
|
+
|
|
46
|
+
const StackedBarchartProm = currentDf.plot.fromType('StackedBarChartAA');
|
|
47
|
+
addViewerToHeader(tableGrid, StackedBarchartProm);
|
|
48
|
+
|
|
49
|
+
const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
|
|
50
|
+
const viewers = [];
|
|
51
|
+
for (const viewer of view.viewers) {
|
|
52
|
+
if (viewer.type !== DG.VIEWER.GRID) {
|
|
53
|
+
viewers.push(viewer);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
viewers.forEach((v) => v.close());
|
|
57
|
+
|
|
58
|
+
const cols = (view.dataFrame.columns as DG.ColumnList);
|
|
59
|
+
for (const colName of cols.names()) {
|
|
60
|
+
if (!originalDfColumns.includes(colName)) {
|
|
61
|
+
cols.remove(colName);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
tableGrid.setOptions({'colHeaderHeight': 20});
|
|
66
|
+
tableGrid.columns.setVisible(originalDfColumns);
|
|
67
|
+
|
|
68
|
+
view.setRibbonPanels(ribbonPanels);
|
|
69
|
+
}, 'Close viewers and restore dataframe');
|
|
70
|
+
|
|
71
|
+
const ribbonPanels = view.getRibbonPanels();
|
|
72
|
+
view.setRibbonPanels([[hideIcon]]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -23,24 +23,27 @@ export function expandColumn(col:DG.Column,
|
|
|
23
23
|
timeout);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function setAARRenderer(col:DG.Column, grid:DG.Grid|null = null) {
|
|
26
|
+
export function setAARRenderer(col: DG.Column, grid: DG.Grid | null = null, grouping = false) {
|
|
27
27
|
col.semType = 'aminoAcids';
|
|
28
28
|
col.setTag('cell.renderer', 'aminoAcids');
|
|
29
|
-
if (
|
|
29
|
+
if (grouping) {
|
|
30
|
+
col.setTag('groups', `${grouping}`);
|
|
31
|
+
}
|
|
32
|
+
if (grid) {
|
|
30
33
|
expandColumn(col, grid, (ent) => measureAAR(ent));
|
|
34
|
+
}
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export function measureAAR(s: string): number {
|
|
34
38
|
const end = s.lastIndexOf(')');
|
|
35
39
|
const beg = s.indexOf('(');
|
|
36
|
-
return end == beg ? s.length:s.length - (end-beg)+1;
|
|
40
|
+
return end == beg ? s.length : s.length - (end - beg) + 1;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
function printLeftCentered(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
x: number, y: number, w: number, h: number,
|
|
45
|
+
g: CanvasRenderingContext2D, s: string, color = ChemPalette.undefinedColor,
|
|
46
|
+
pivot: number = 0, left = false, hideMod = false) {
|
|
44
47
|
g.textAlign = 'start';
|
|
45
48
|
let colorPart = pivot == -1 ? s.substring(0) : s.substring(0, pivot);
|
|
46
49
|
if (colorPart.length == 1) {
|
|
@@ -91,8 +94,7 @@ function printLeftCentered(
|
|
|
91
94
|
if (left || textSize.width > w) {
|
|
92
95
|
draw(indent, indent + colorTextSize.width);
|
|
93
96
|
return x + colorTextSize.width + g.measureText(grayPart).width;
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
97
|
+
} else {
|
|
96
98
|
draw((w - textSize.width) / 2, (w - textSize.width) / 2 + colorTextSize.width);
|
|
97
99
|
return x + (w - textSize.width) / 2 + colorTextSize.width;
|
|
98
100
|
}
|
|
@@ -100,13 +102,26 @@ function printLeftCentered(
|
|
|
100
102
|
|
|
101
103
|
|
|
102
104
|
export class AminoAcidsCellRenderer extends DG.GridCellRenderer {
|
|
105
|
+
chemPalette: ChemPalette | null;
|
|
106
|
+
|
|
107
|
+
get name() {
|
|
108
|
+
return 'aminoAcidsCR';
|
|
109
|
+
}
|
|
103
110
|
|
|
104
|
-
get
|
|
111
|
+
get cellType() {
|
|
112
|
+
return 'aminoAcids';
|
|
113
|
+
}
|
|
105
114
|
|
|
106
|
-
|
|
115
|
+
constructor() {
|
|
116
|
+
super();
|
|
117
|
+
this.chemPalette = null;
|
|
118
|
+
}
|
|
107
119
|
|
|
108
120
|
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
109
|
-
|
|
121
|
+
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle) {
|
|
122
|
+
if (this.chemPalette === null) {
|
|
123
|
+
this.chemPalette = new ChemPalette('grok', gridCell.tableColumn?.getTag('groups') ? true : false);
|
|
124
|
+
}
|
|
110
125
|
g.save();
|
|
111
126
|
g.beginPath();
|
|
112
127
|
g.rect(x, y, w, h);
|
|
@@ -122,44 +137,47 @@ export class AminoAcidsCellRenderer extends DG.GridCellRenderer {
|
|
|
122
137
|
|
|
123
138
|
|
|
124
139
|
export class AlignedSequenceCellRenderer extends DG.GridCellRenderer {
|
|
140
|
+
get name() {
|
|
141
|
+
return 'alignedSequenceCR';
|
|
142
|
+
}
|
|
125
143
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
131
|
-
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle ) {
|
|
132
|
-
w = Math.min(gridCell.grid.canvas.width - x, w);
|
|
133
|
-
g.save();
|
|
134
|
-
g.beginPath();
|
|
135
|
-
g.rect(x, y, w, h);
|
|
136
|
-
g.clip();
|
|
137
|
-
g.font = '14px monospace';
|
|
138
|
-
g.textBaseline = 'top';
|
|
139
|
-
const s: string = gridCell.cell.value ?? '';
|
|
140
|
-
|
|
141
|
-
const subParts = s.split('-');
|
|
142
|
-
const [text, simplified] = processSequence(subParts);
|
|
143
|
-
const textSize = g.measureText(text.join(''));
|
|
144
|
-
x = Math.max(x, x + (w - textSize.width) / 2);
|
|
145
|
-
|
|
146
|
-
subParts.forEach((amino: string, index) => {
|
|
147
|
-
const [color, pivot] = cp.getColorPivot(amino);
|
|
148
|
-
g.fillStyle = ChemPalette.undefinedColor;
|
|
149
|
-
if (index + 1 < subParts.length) {
|
|
150
|
-
const gap = simplified?'':' ';
|
|
151
|
-
amino += `${amino?'':'-'}${gap}`;
|
|
152
|
-
}
|
|
153
|
-
x = printLeftCentered(x, y, w, h, g, amino, color, pivot, true);
|
|
154
|
-
});
|
|
144
|
+
get cellType() {
|
|
145
|
+
return 'alignedSequence';
|
|
146
|
+
}
|
|
155
147
|
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
149
|
+
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle ) {
|
|
150
|
+
w = Math.min(gridCell.grid.canvas.width - x, w);
|
|
151
|
+
g.save();
|
|
152
|
+
g.beginPath();
|
|
153
|
+
g.rect(x, y, w, h);
|
|
154
|
+
g.clip();
|
|
155
|
+
g.font = '14px monospace';
|
|
156
|
+
g.textBaseline = 'top';
|
|
157
|
+
const s: string = gridCell.cell.value ?? '';
|
|
158
|
+
|
|
159
|
+
//TODO: can this be replaced/merged with splitSequence?
|
|
160
|
+
const subParts = s.split('-');
|
|
161
|
+
const [text, simplified] = processSequence(subParts);
|
|
162
|
+
const textSize = g.measureText(text.join(''));
|
|
163
|
+
x = Math.max(x, x + (w - textSize.width) / 2);
|
|
164
|
+
|
|
165
|
+
subParts.forEach((amino: string, index) => {
|
|
166
|
+
const [color, pivot] = cp.getColorPivot(amino);
|
|
167
|
+
g.fillStyle = ChemPalette.undefinedColor;
|
|
168
|
+
if (index + 1 < subParts.length) {
|
|
169
|
+
const gap = simplified?'':' ';
|
|
170
|
+
amino += `${amino?'':'-'}${gap}`;
|
|
171
|
+
}
|
|
172
|
+
x = printLeftCentered(x, y, w, h, g, amino, color, pivot, true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
g.restore();
|
|
176
|
+
}
|
|
158
177
|
}
|
|
159
178
|
|
|
160
179
|
|
|
161
180
|
export function processSequence(subParts:string[]) : [string[], boolean] {
|
|
162
|
-
|
|
163
181
|
const simplified = !subParts.some((amino, index) =>
|
|
164
182
|
amino.length > 1 &&
|
|
165
183
|
index != 0 &&
|
|
@@ -174,4 +192,4 @@ export function processSequence(subParts:string[]) : [string[], boolean] {
|
|
|
174
192
|
text.push(amino);
|
|
175
193
|
});
|
|
176
194
|
return [text, simplified];
|
|
177
|
-
}
|
|
195
|
+
}
|
|
@@ -6,17 +6,16 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
export class ChemPalette {
|
|
7
7
|
cp: {[key: string]: string} = {};
|
|
8
8
|
|
|
9
|
-
constructor(scheme: string) {
|
|
9
|
+
constructor(scheme: string, grouping = false) {
|
|
10
10
|
if (scheme == 'grok') {
|
|
11
|
-
this.cp = ChemPalette.getDatagrok();
|
|
11
|
+
this.cp = ChemPalette.getDatagrok(grouping);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
showTooltip(cell:DG.GridCell, x:number, y:number) {
|
|
16
16
|
const s = cell.cell.value as string;
|
|
17
17
|
let toDisplay = [ui.divText(s)];
|
|
18
|
-
|
|
19
|
-
const [_c, aar, _p] = this.getColorAAPivot(s);
|
|
18
|
+
const [, aar] = this.getColorAAPivot(s);
|
|
20
19
|
if (aar in ChemPalette.AASmiles) {
|
|
21
20
|
if (s in ChemPalette.AANames) {
|
|
22
21
|
toDisplay = [ui.divText(ChemPalette.AANames[s])];
|
|
@@ -31,8 +30,7 @@ export class ChemPalette {
|
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
getColor( c: string) {
|
|
34
|
-
|
|
35
|
-
const [color, _] = this.getColorPivot(c);
|
|
33
|
+
const [color] = this.getColorPivot(c);
|
|
36
34
|
return color;
|
|
37
35
|
}
|
|
38
36
|
|
|
@@ -77,8 +75,7 @@ export class ChemPalette {
|
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
getColorPivot(c = ''): [string, number] {
|
|
80
|
-
|
|
81
|
-
const [color, _, pivot] = this.getColorAAPivot(c);
|
|
78
|
+
const [color,, pivot] = this.getColorAAPivot(c);
|
|
82
79
|
return [color, pivot];
|
|
83
80
|
};
|
|
84
81
|
|
|
@@ -130,14 +127,17 @@ export class ChemPalette {
|
|
|
130
127
|
'all_blue': ['K', 'R'],
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
static undefinedColor = 'rgb(100,100,100)'
|
|
130
|
+
static undefinedColor = 'rgb(100,100,100)';
|
|
134
131
|
|
|
135
|
-
static makePalette(dt: {[key: string]: string[]}, simplified = false) {
|
|
132
|
+
static makePalette(dt: {[key: string]: string[]}, simplified = false, grouping = false) {
|
|
136
133
|
const palette: { [key: string]: string } = {};
|
|
134
|
+
const groups = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
135
|
+
let currentGroup = 0;
|
|
137
136
|
for (const [color, monomers] of Object.entries(dt)) {
|
|
138
137
|
monomers.forEach((monomer, index) => {
|
|
139
|
-
palette[monomer] = ChemPalette.colourPalette[color][simplified ? 0 : index];
|
|
138
|
+
palette[grouping ? groups[currentGroup] : monomer] = ChemPalette.colourPalette[color][simplified ? 0 : index];
|
|
140
139
|
});
|
|
140
|
+
currentGroup++;
|
|
141
141
|
}
|
|
142
142
|
return palette;
|
|
143
143
|
}
|
|
@@ -234,8 +234,8 @@ export class ChemPalette {
|
|
|
234
234
|
'Val': 'V',
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
static getDatagrok() {
|
|
238
|
-
return ChemPalette.makePalette(ChemPalette.grokGroups);
|
|
237
|
+
static getDatagrok(grouping = false) {
|
|
238
|
+
return ChemPalette.makePalette(ChemPalette.grokGroups, false, grouping);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
static getLesk() {
|
|
@@ -4,17 +4,28 @@
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
6
|
import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
|
|
7
|
-
import {assert, transposeMatrix
|
|
8
|
-
import {Vector} from '@datagrok-libraries/utils/src/
|
|
7
|
+
import {assert, transposeMatrix} from '@datagrok-libraries/utils/src/operations';
|
|
8
|
+
import {Vector, Matrix} from '@datagrok-libraries/utils/src/type-declarations';
|
|
9
|
+
import {kendallsTau} from '@datagrok-libraries/statistics/src/correlation-coefficient';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
+
* Converts a Matrix into a DataFrame.
|
|
12
13
|
*
|
|
13
14
|
* @export
|
|
15
|
+
* @param {Matrix} matrix A matrix.
|
|
16
|
+
* @return {DG.DataFrame} The data frame.
|
|
17
|
+
*/
|
|
18
|
+
export function matrix2DataFrame(matrix: Matrix): DG.DataFrame {
|
|
19
|
+
return DG.DataFrame.fromColumns(matrix.map((v, i) => DG.Column.fromFloat32Array(`${i+1}`, v)));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Encodes amino acid sequences into a numeric representation.
|
|
24
|
+
*
|
|
14
25
|
* @param {DG.Column} col A column containing the sequences.
|
|
15
26
|
* @return {DG.DataFrame} The resulting data frame.
|
|
16
27
|
*/
|
|
17
|
-
|
|
28
|
+
function calcPositions(col: DG.Column): DG.DataFrame {
|
|
18
29
|
const sequences = col.toList().map((v, _) => AlignedSequenceEncoder.clean(v));
|
|
19
30
|
const enc = new AlignedSequenceEncoder();
|
|
20
31
|
const encSeqs = sequences.map((v) => Vector.from(enc.encode(v)));
|
|
@@ -25,11 +36,10 @@ export function calcPositions(col: DG.Column): DG.DataFrame {
|
|
|
25
36
|
/**
|
|
26
37
|
* Unfolds a data frame into <category>-<value> format.
|
|
27
38
|
*
|
|
28
|
-
* @export
|
|
29
39
|
* @param {DG.DataFrame} df A data frame to unfold.
|
|
30
40
|
* @return {DG.DataFrame} The resulting data frame.
|
|
31
41
|
*/
|
|
32
|
-
|
|
42
|
+
function melt(df: DG.DataFrame): DG.DataFrame {
|
|
33
43
|
let keys: string[] = [];
|
|
34
44
|
const values: Float32Array = new Float32Array(df.columns.length*df.rowCount);
|
|
35
45
|
let i = 0;
|
|
@@ -43,38 +53,45 @@ export function melt(df: DG.DataFrame): DG.DataFrame {
|
|
|
43
53
|
return DG.DataFrame.fromColumns([DG.Column.fromStrings('keys', keys), DG.Column.fromFloat32Array('values', values)]);
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Calculates Spearman's rho rank correlation coefficient.
|
|
58
|
+
*
|
|
59
|
+
* @param {DG.DataFrame} df A data frame to process.
|
|
60
|
+
* @return {DG.DataFrame} The correlation matrix.
|
|
61
|
+
*/
|
|
62
|
+
// eslint-disable-next-line no-unused-vars
|
|
63
|
+
function calcSpearmanRhoMatrix(df: DG.DataFrame): DG.DataFrame {
|
|
64
|
+
const nItems = df.columns.length;
|
|
49
65
|
const rho = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
|
|
50
66
|
|
|
51
67
|
for (let i = 0; i < nItems; ++i) {
|
|
52
68
|
for (let j = i+1; j < nItems; ++j) {
|
|
53
|
-
rho[i][j] =
|
|
69
|
+
rho[i][j] = df.columns.byIndex(i).stats.spearmanCorr(df.columns.byIndex(j));
|
|
54
70
|
rho[j][i] = rho[i][j];
|
|
55
71
|
}
|
|
56
72
|
}
|
|
57
|
-
return rho;
|
|
58
|
-
}
|
|
73
|
+
return matrix2DataFrame(rho);
|
|
74
|
+
}
|
|
59
75
|
|
|
60
76
|
/**
|
|
61
|
-
* Calculates
|
|
77
|
+
* Calculates Kendall's tau rank correlation coefficient.
|
|
62
78
|
*
|
|
63
|
-
* @export
|
|
64
79
|
* @param {DG.DataFrame} df A data frame to process.
|
|
80
|
+
* @param {number} [alpha=0.05] The significance threshold.
|
|
65
81
|
* @return {DG.DataFrame} The correlation matrix.
|
|
66
82
|
*/
|
|
67
|
-
|
|
83
|
+
function calcKendallTauMatrix(df: DG.DataFrame, alpha: number = 0.05): DG.DataFrame {
|
|
68
84
|
const nItems = df.columns.length;
|
|
69
|
-
const
|
|
85
|
+
const tau = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
|
|
70
86
|
|
|
71
87
|
for (let i = 0; i < nItems; ++i) {
|
|
72
88
|
for (let j = i+1; j < nItems; ++j) {
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
const res = kendallsTau(df.columns.byIndex(i).getRawData(), df.columns.byIndex(j).getRawData());
|
|
90
|
+
tau[i][j] = res.prob < alpha ? res.test : 0;
|
|
91
|
+
tau[j][i] = tau[i][j];
|
|
75
92
|
}
|
|
76
93
|
}
|
|
77
|
-
return matrix2DataFrame(
|
|
94
|
+
return matrix2DataFrame(tau);
|
|
78
95
|
}
|
|
79
96
|
|
|
80
97
|
/**
|
|
@@ -95,7 +112,7 @@ export function correlationAnalysisPlots(sequencesColumn: DG.Column): [DG.Viewer
|
|
|
95
112
|
'correlationType': 'Spearman',
|
|
96
113
|
});
|
|
97
114
|
|
|
98
|
-
const rhoDF =
|
|
115
|
+
const rhoDF = calcKendallTauMatrix(posDF);
|
|
99
116
|
const meltDF = melt(rhoDF);
|
|
100
117
|
|
|
101
118
|
const bpviewer = DG.Viewer.fromType(
|
|
@@ -8,7 +8,7 @@ import {getSequenceMolecularWeight} from './molecular-measure';
|
|
|
8
8
|
import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
|
|
9
9
|
import {DimensionalityReducer} from '@datagrok-libraries/utils/src/reduce-dimensionality';
|
|
10
10
|
import {Measurer} from '@datagrok-libraries/utils/src/string-measure';
|
|
11
|
-
import {Coordinates} from '@datagrok-libraries/utils/src/
|
|
11
|
+
import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Creates a worker to perform a dimensionality reduction.
|
|
@@ -75,6 +75,7 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
75
75
|
method: string,
|
|
76
76
|
measure: string,
|
|
77
77
|
cyclesCount: number,
|
|
78
|
+
view: DG.TableView | null,
|
|
78
79
|
activityColumnName?: string | null,
|
|
79
80
|
zoom: boolean = false,
|
|
80
81
|
): Promise<DG.ScatterPlotViewer> {
|
|
@@ -117,8 +118,11 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
117
118
|
table.columns.replace(col, edf.getCol(axis));
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
|
-
const viewer = DG.Viewer.scatterPlot(table, {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'});
|
|
121
121
|
|
|
122
|
+
// const viewer = DG.Viewer.scatterPlot(table, {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'});
|
|
123
|
+
const viewerOptions = {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'};
|
|
124
|
+
const viewer = view !== null ?
|
|
125
|
+
view.addViewer(DG.VIEWER.SCATTER_PLOT, viewerOptions) : DG.Viewer.scatterPlot(table, viewerOptions);
|
|
122
126
|
// Fit view if needed.
|
|
123
127
|
/*if (zoom) {
|
|
124
128
|
viewer.zoom(
|
|
@@ -129,7 +133,7 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
129
133
|
);
|
|
130
134
|
}*/
|
|
131
135
|
pi.close();
|
|
132
|
-
return viewer;
|
|
136
|
+
return (viewer as DG.ScatterPlotViewer);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
/**
|
|
@@ -147,13 +151,14 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
147
151
|
protected availableMethods: string[];
|
|
148
152
|
protected availableMetrics: string[];
|
|
149
153
|
protected viewer: HTMLElement;
|
|
154
|
+
view: DG.TableView;
|
|
150
155
|
|
|
151
156
|
/**
|
|
152
157
|
* Creates an instance of PeptideSimilaritySpaceWidget.
|
|
153
158
|
* @param {DG.Column} alignedSequencesColumn The column to get amino acid sequences from.
|
|
154
159
|
* @memberof PeptideSimilaritySpaceWidget
|
|
155
160
|
*/
|
|
156
|
-
constructor(alignedSequencesColumn: DG.Column) {
|
|
161
|
+
constructor(alignedSequencesColumn: DG.Column, view: DG.TableView) {
|
|
157
162
|
this.availableMethods = DimensionalityReducer.availableMethods;
|
|
158
163
|
this.availableMetrics = Measurer.availableMeasures;
|
|
159
164
|
this.method = this.availableMethods[0];
|
|
@@ -161,6 +166,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
161
166
|
this.currentDf = alignedSequencesColumn.dataFrame;
|
|
162
167
|
this.alignedSequencesColumn = alignedSequencesColumn;
|
|
163
168
|
this.viewer = ui.div([]);
|
|
169
|
+
this.view = view;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
/**
|
|
@@ -177,6 +183,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
177
183
|
this.metrics,
|
|
178
184
|
this.cycles,
|
|
179
185
|
null,
|
|
186
|
+
null,
|
|
180
187
|
true,
|
|
181
188
|
);
|
|
182
189
|
viewer.root.style.width = 'auto';
|
|
@@ -45,7 +45,7 @@ export function splitAlignedPeptides(peptideColumn: DG.Column, filter: boolean =
|
|
|
45
45
|
columnNames.push('C-terminal');
|
|
46
46
|
|
|
47
47
|
// filter out the columns with the same values
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
if (filter) {
|
|
50
50
|
splitColumns = splitColumns.filter((positionArray, index) => {
|
|
51
51
|
const isRetained = new Set(positionArray).size > 1;
|
package/src/viewers/model.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
|
|
3
3
|
import {describe} from '../describe';
|
|
4
|
-
import {
|
|
4
|
+
import {Subject} from 'rxjs';
|
|
5
5
|
|
|
6
6
|
class SARViewerModel {
|
|
7
7
|
private viewerGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
|
|
8
8
|
private viewerVGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
|
|
9
9
|
private statsDf: Subject<DG.DataFrame> = new Subject<DG.DataFrame>();
|
|
10
|
-
|
|
11
|
-
public
|
|
12
|
-
public
|
|
10
|
+
private groupMapping: Subject<{[key: string]: string}> = new Subject<{[key: string]: string}>();
|
|
11
|
+
public viewerGrid$;
|
|
12
|
+
public viewerVGrid$;
|
|
13
|
+
public statsDf$;
|
|
14
|
+
public groupMapping$;
|
|
13
15
|
private dataFrame: DG.DataFrame | null;
|
|
14
16
|
private activityColumn: string | null;
|
|
15
17
|
private activityScaling: string | null;
|
|
@@ -17,6 +19,7 @@ class SARViewerModel {
|
|
|
17
19
|
private twoColorMode: boolean | null;
|
|
18
20
|
private initialBitset: DG.BitSet | null;
|
|
19
21
|
private isUpdating = false;
|
|
22
|
+
grouping: boolean;
|
|
20
23
|
|
|
21
24
|
constructor() {
|
|
22
25
|
this.dataFrame = null;
|
|
@@ -25,39 +28,49 @@ class SARViewerModel {
|
|
|
25
28
|
this.sourceGrid = null;
|
|
26
29
|
this.twoColorMode = null;
|
|
27
30
|
this.initialBitset = null;
|
|
31
|
+
this.grouping = false;
|
|
32
|
+
this.viewerGrid$ = this.viewerGrid.asObservable();
|
|
33
|
+
this.viewerVGrid$ = this.viewerVGrid.asObservable();
|
|
34
|
+
this.statsDf$ = this.statsDf.asObservable();
|
|
35
|
+
this.groupMapping$ = this.groupMapping.asObservable();
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
async updateData(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
df: DG.DataFrame,
|
|
40
|
+
activityCol: string,
|
|
41
|
+
activityScaling: string,
|
|
42
|
+
sourceGrid: DG.Grid,
|
|
43
|
+
twoColorMode: boolean,
|
|
44
|
+
initialBitset: DG.BitSet | null,
|
|
45
|
+
grouping: boolean,
|
|
46
|
+
) {
|
|
38
47
|
this.dataFrame = df;
|
|
39
48
|
this.activityColumn = activityCol;
|
|
40
49
|
this.activityScaling = activityScaling;
|
|
41
50
|
this.sourceGrid = sourceGrid;
|
|
42
51
|
this.twoColorMode = twoColorMode;
|
|
43
52
|
this.initialBitset = initialBitset;
|
|
53
|
+
this.grouping = grouping;
|
|
44
54
|
await this.updateDefault();
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
async updateDefault() {
|
|
48
|
-
if (
|
|
58
|
+
if (
|
|
59
|
+
this.dataFrame && this.activityColumn && this.activityScaling &&
|
|
60
|
+
this.sourceGrid && this.twoColorMode !== null && !this.isUpdating
|
|
61
|
+
) {
|
|
49
62
|
this.isUpdating = true;
|
|
50
|
-
const [viewerGrid, viewerVGrid, statsDf] = await describe(
|
|
63
|
+
const [viewerGrid, viewerVGrid, statsDf, groupMapping] = await describe(
|
|
51
64
|
this.dataFrame, this.activityColumn, this.activityScaling,
|
|
52
|
-
this.sourceGrid, this.twoColorMode, this.initialBitset
|
|
65
|
+
this.sourceGrid, this.twoColorMode, this.initialBitset, this.grouping,
|
|
53
66
|
);
|
|
54
67
|
this.viewerGrid.next(viewerGrid);
|
|
55
68
|
this.viewerVGrid.next(viewerVGrid);
|
|
56
69
|
this.statsDf.next(statsDf);
|
|
70
|
+
this.groupMapping.next(groupMapping);
|
|
57
71
|
this.isUpdating = false;
|
|
58
72
|
}
|
|
59
73
|
}
|
|
60
74
|
}
|
|
61
75
|
|
|
62
|
-
export
|
|
63
|
-
|
|
76
|
+
export const model = new SARViewerModel();
|
|
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {model} from './model';
|
|
8
8
|
|
|
9
9
|
export class SARViewer extends DG.JsViewer {
|
|
10
10
|
protected viewerGrid: DG.Grid | null;
|
|
@@ -20,16 +20,19 @@ export class SARViewer extends DG.JsViewer {
|
|
|
20
20
|
protected _initialBitset: DG.BitSet | null;
|
|
21
21
|
protected viewerVGrid: DG.Grid | null;
|
|
22
22
|
protected currentBitset: DG.BitSet | null;
|
|
23
|
+
grouping: boolean;
|
|
24
|
+
groupMapping: {[key: string]: string} | null;
|
|
23
25
|
// private df: DG.DataFrame | null;
|
|
24
26
|
// protected pValueThreshold: number;
|
|
25
27
|
// protected amountOfBestAARs: number;
|
|
26
28
|
// duplicatesHandingMethod: string;
|
|
27
29
|
constructor() {
|
|
28
30
|
super();
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
this.viewerGrid = null;
|
|
31
33
|
this.viewerVGrid = null;
|
|
32
34
|
this.statsDf = null;
|
|
35
|
+
this.groupMapping = null;
|
|
33
36
|
this.initialized = false;
|
|
34
37
|
this.aminoAcidResidue = 'AAR';
|
|
35
38
|
this._initialBitset = null;
|
|
@@ -41,6 +44,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
41
44
|
this.activityScalingMethod = this.string('activityScalingMethod', 'none', {choices: ['none', 'lg', '-lg']});
|
|
42
45
|
this.filterMode = this.bool('filterMode', false);
|
|
43
46
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
47
|
+
this.grouping = this.bool('grouping', false);
|
|
44
48
|
// this.pValueThreshold = this.float('pValueThreshold', 0.1);
|
|
45
49
|
// this.amountOfBestAARs = this.int('amountOfBestAAR', 1);
|
|
46
50
|
// this.duplicatesHandingMethod = this.string('duplicatesHandlingMethod', 'median', {choices: ['median']});
|
|
@@ -51,12 +55,13 @@ export class SARViewer extends DG.JsViewer {
|
|
|
51
55
|
init() {
|
|
52
56
|
this._initialBitset = this.dataFrame!.filter.clone();
|
|
53
57
|
this.initialized = true;
|
|
54
|
-
this.subs.push(model.statsDf$.subscribe(data => this.statsDf = data));
|
|
55
|
-
this.subs.push(model.viewerGrid$.subscribe(data => {
|
|
58
|
+
this.subs.push(model.statsDf$.subscribe((data) => this.statsDf = data));
|
|
59
|
+
this.subs.push(model.viewerGrid$.subscribe((data) => {
|
|
56
60
|
this.viewerGrid = data;
|
|
57
61
|
this.render();
|
|
58
62
|
}));
|
|
59
|
-
this.subs.push(model.viewerVGrid$.subscribe(data => this.viewerVGrid = data));
|
|
63
|
+
this.subs.push(model.viewerVGrid$.subscribe((data) => this.viewerVGrid = data));
|
|
64
|
+
this.subs.push(model.groupMapping$.subscribe((data) => this.groupMapping = data));
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
onTableAttached() {
|
|
@@ -114,7 +119,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
114
119
|
splitCol = this.dataFrame.columns.addNew(splitColName, 'string');
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
const isChosen = (i: number) => this.dataFrame!.get(currentPosition, i) === currentAAR;
|
|
122
|
+
const isChosen = (i: number) => this.groupMapping![this.dataFrame!.get(currentPosition, i)] === currentAAR;
|
|
118
123
|
splitCol!.init((i) => isChosen(i) ? aarLabel : otherLabel);
|
|
119
124
|
|
|
120
125
|
//TODO: use column.compact
|
|
@@ -277,6 +282,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
277
282
|
this.sourceGrid,
|
|
278
283
|
this.bidirectionalAnalysis,
|
|
279
284
|
this._initialBitset,
|
|
285
|
+
this.grouping,
|
|
280
286
|
);
|
|
281
287
|
|
|
282
288
|
if (this.viewerGrid !== null && this.viewerVGrid !== null) {
|
|
@@ -303,7 +309,7 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
303
309
|
super();
|
|
304
310
|
|
|
305
311
|
this.viewerVGrid = null;
|
|
306
|
-
this.subs.push(model.viewerVGrid$.subscribe(data => {
|
|
312
|
+
this.subs.push(model.viewerVGrid$.subscribe((data) => {
|
|
307
313
|
this.viewerVGrid = data;
|
|
308
314
|
this.render();
|
|
309
315
|
}));
|
|
@@ -316,4 +322,4 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
316
322
|
}
|
|
317
323
|
this.viewerVGrid?.invalidate();
|
|
318
324
|
}
|
|
319
|
-
}
|
|
325
|
+
}
|
|
@@ -115,8 +115,8 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
115
115
|
let i = 0;
|
|
116
116
|
for (const value of Object.values(groups)) {
|
|
117
117
|
i++;
|
|
118
|
-
for (const obj
|
|
119
|
-
this.ord[
|
|
118
|
+
for (const obj of value) {
|
|
119
|
+
this.ord[obj] = i;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
this.yScale = scaleLinear();
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
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
|
-
import {
|
|
5
|
-
import {addViewerToHeader} from '../viewers/stacked-barchart-viewer';
|
|
6
|
-
import {model} from '../viewers/model';
|
|
4
|
+
import { Peptides } from '../peptides';
|
|
7
5
|
|
|
8
6
|
export async function analyzePeptidesWidget(
|
|
9
7
|
col: DG.Column, view: DG.TableView, tableGrid: DG.Grid, currentDf: DG.DataFrame,
|
|
@@ -24,6 +22,7 @@ export async function analyzePeptidesWidget(
|
|
|
24
22
|
async (currentMethod: string) => {
|
|
25
23
|
const currentActivityCol = activityColumnChoice.value.name;
|
|
26
24
|
const tempDf = currentDf.clone(currentDf.filter, [currentActivityCol]);
|
|
25
|
+
//TODO: merge with scaling in describe
|
|
27
26
|
switch (currentMethod) {
|
|
28
27
|
case 'lg':
|
|
29
28
|
await tempDf.columns.addNewCalculated('scaledActivity', 'Log10(${' + currentActivityCol + '})');
|
|
@@ -64,45 +63,20 @@ export async function analyzePeptidesWidget(
|
|
|
64
63
|
activityScalingMethod.fireChanged();
|
|
65
64
|
|
|
66
65
|
const startBtn = ui.button('Launch SAR', async () => {
|
|
67
|
-
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
68
66
|
if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
|
|
67
|
+
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
69
68
|
const options: {[key: string]: string} = {
|
|
70
69
|
'activityColumnColumnName': activityColumnChoice.value.name,
|
|
71
70
|
'activityScalingMethod': activityScalingMethod.value,
|
|
72
71
|
};
|
|
73
|
-
for (let i = 0; i < tableGrid.columns.length; i++) {
|
|
74
|
-
const col = tableGrid.columns.byIndex(i);
|
|
75
|
-
if (col &&
|
|
76
|
-
col.name &&
|
|
77
|
-
col.column?.semType != 'aminoAcids'
|
|
78
|
-
) {
|
|
79
|
-
//@ts-ignore
|
|
80
|
-
tableGrid.columns.byIndex(i)?.visible = false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
72
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
|
|
87
|
-
currentDf,
|
|
88
|
-
col,
|
|
89
|
-
't-SNE',
|
|
90
|
-
'Levenshtein',
|
|
91
|
-
100,
|
|
92
|
-
`${activityColumnChoice}Scaled`,
|
|
93
|
-
);
|
|
94
|
-
let refNode = view.dockManager.dock(peptideSpaceViewer, 'down');
|
|
95
|
-
refNode = view.dockManager.dock(sarViewer, 'right', refNode);
|
|
96
|
-
view.dockManager.dock(sarViewerVertical, 'right', refNode);
|
|
73
|
+
let peptides = new Peptides();
|
|
74
|
+
await peptides.init(tableGrid, view, currentDf, options, col, activityColumnChoice.value.name);
|
|
97
75
|
|
|
98
|
-
|
|
99
|
-
addViewerToHeader(tableGrid, StackedBarchartProm);
|
|
100
|
-
|
|
101
|
-
// currentDf.onValuesChanged.subscribe(async () => await model.updateDefault());
|
|
76
|
+
progress.close();
|
|
102
77
|
} else {
|
|
103
78
|
grok.shell.error('The activity column must be of floating point number type!');
|
|
104
79
|
}
|
|
105
|
-
progress.close();
|
|
106
80
|
});
|
|
107
81
|
|
|
108
82
|
const viewer = await currentDf.plot.fromType('peptide-logo-viewer');
|
|
@@ -2,8 +2,8 @@ import * as ui from 'datagrok-api/ui';
|
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
|
|
4
4
|
import $ from 'cash-dom';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import {model} from '../viewers/model';
|
|
6
|
+
import {splitAlignedPeptides} from '../utils/split-aligned';
|
|
7
7
|
|
|
8
8
|
export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf: DG.DataFrame) {
|
|
9
9
|
const sequenceInput = ui.textInput('', alignedSequenceCol.get(currentDf.currentRowIdx));
|
|
@@ -13,12 +13,13 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf:
|
|
|
13
13
|
const applyChangesBtn = ui.button('Apply', async () => {
|
|
14
14
|
const newSequence = sequenceInput.value;
|
|
15
15
|
const affectedRowIndex = currentDf.currentRowIdx;
|
|
16
|
-
const [splitSequence
|
|
16
|
+
const [splitSequence] = splitAlignedPeptides(DG.Column.fromStrings('splitSequence', [newSequence]), false);
|
|
17
17
|
|
|
18
18
|
alignedSequenceCol.set(affectedRowIndex, newSequence);
|
|
19
19
|
for (const part of splitSequence.columns) {
|
|
20
|
-
if (currentDf.col(part.name) !== null)
|
|
20
|
+
if (currentDf.col(part.name) !== null) {
|
|
21
21
|
currentDf.set(part.name, affectedRowIndex, part.get(0));
|
|
22
|
+
}
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
await model.updateDefault();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {DimensionalityReducer} from '@datagrok-libraries/utils/src/reduce-dimensionality';
|
|
2
|
-
import {Coordinates} from '@datagrok-libraries/utils/src/
|
|
2
|
+
import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Worker thread receiving data function.
|