@datagrok/peptides 0.2.0 → 0.4.3
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 +5 -5
- package/src/describe.ts +81 -40
- package/src/package.ts +15 -25
- package/src/peptides.ts +76 -0
- package/src/utils/cell-renderer.ts +63 -45
- package/src/utils/chem-palette.ts +19 -22
- package/src/utils/correlation-analysis.ts +123 -0
- package/src/utils/peptide-similarity-space.ts +13 -15
- package/src/utils/split-aligned.ts +0 -1
- package/src/viewers/logo-viewer.ts +0 -5
- package/src/viewers/model.ts +29 -16
- package/src/viewers/sar-viewer.ts +14 -29
- package/src/viewers/stacked-barchart-viewer.ts +3 -7
- 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,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@keckelt/tsne": "^1.0.2",
|
|
7
7
|
"cash-dom": "latest",
|
|
8
8
|
"d3": "latest",
|
|
9
|
-
"datagrok-api": "
|
|
9
|
+
"datagrok-api": ">=0.95.11",
|
|
10
10
|
"dayjs": "latest",
|
|
11
11
|
"jaro-winkler-typescript": "^1.0.1",
|
|
12
12
|
"jstat": "^1.9.5",
|
|
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
|
},
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"lint": "eslint \"./src/**/*.ts\"",
|
|
53
53
|
"lint-fix": "eslint \"./src/**/*.ts\" --fix"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|
package/src/describe.ts
CHANGED
|
@@ -1,15 +1,50 @@
|
|
|
1
|
-
// eslint-disable-next-line no-unused-vars
|
|
2
|
-
import * as grok from 'datagrok-api/grok';
|
|
3
1
|
import * as ui from 'datagrok-api/ui';
|
|
4
2
|
import * as DG from 'datagrok-api/dg';
|
|
5
3
|
import {splitAlignedPeptides} from './utils/split-aligned';
|
|
6
4
|
import {tTest} from '@datagrok-libraries/statistics/src/tests';
|
|
7
|
-
import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests
|
|
5
|
+
import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests';
|
|
8
6
|
import {ChemPalette} from './utils/chem-palette';
|
|
9
7
|
import {setAARRenderer} from './utils/cell-renderer';
|
|
10
8
|
|
|
11
9
|
const cp = new ChemPalette('grok');
|
|
12
10
|
|
|
11
|
+
const aarGroups = {
|
|
12
|
+
'R': 'PC',
|
|
13
|
+
'H': 'PC',
|
|
14
|
+
'K': 'PC',
|
|
15
|
+
'D': 'NC',
|
|
16
|
+
'E': 'NC',
|
|
17
|
+
'S': 'U',
|
|
18
|
+
'T': 'U',
|
|
19
|
+
'N': 'U',
|
|
20
|
+
'Q': 'U',
|
|
21
|
+
'C': 'SC',
|
|
22
|
+
'U': 'SC',
|
|
23
|
+
'G': 'SC',
|
|
24
|
+
'P': 'SC',
|
|
25
|
+
'A': 'H',
|
|
26
|
+
'V': 'H',
|
|
27
|
+
'I': 'H',
|
|
28
|
+
'L': 'H',
|
|
29
|
+
'M': 'H',
|
|
30
|
+
'F': 'H',
|
|
31
|
+
'Y': 'H',
|
|
32
|
+
'W': 'H',
|
|
33
|
+
'-': '-',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const groupDescription: {[key: string]: {'description': string, 'aminoAcids': string[]}} = {
|
|
37
|
+
'PC': {'description': 'Positive Amino Acids, with Electrically Charged Side Chains', 'aminoAcids': ['R', 'H', 'K']},
|
|
38
|
+
'NC': {'description': 'Negative Amino Acids, with Electrically Charged Side Chains', 'aminoAcids': ['D', 'E']},
|
|
39
|
+
'U': {'description': 'Amino Acids with Polar Uncharged Side Chains', 'aminoAcids': ['S', 'T', 'N', 'Q']},
|
|
40
|
+
'SC': {'description': 'Special Cases', 'aminoAcids': ['C', 'U', 'G', 'P']},
|
|
41
|
+
'H': {
|
|
42
|
+
'description': 'Amino Acids with Hydrophobic Side Chain',
|
|
43
|
+
'aminoAcids': ['A', 'V', 'I', 'L', 'M', 'F', 'Y', 'W'],
|
|
44
|
+
},
|
|
45
|
+
'-': {'description': 'Unknown Amino Acid', 'aminoAcids': ['-']},
|
|
46
|
+
};
|
|
47
|
+
|
|
13
48
|
export async function describe(
|
|
14
49
|
df: DG.DataFrame,
|
|
15
50
|
activityColumn: string,
|
|
@@ -17,7 +52,8 @@ export async function describe(
|
|
|
17
52
|
sourceGrid: DG.Grid,
|
|
18
53
|
twoColorMode: boolean,
|
|
19
54
|
initialBitset: DG.BitSet | null,
|
|
20
|
-
|
|
55
|
+
grouping: boolean,
|
|
56
|
+
): Promise<[DG.Grid, DG.Grid, DG.DataFrame, {[key: string]: string}]> {
|
|
21
57
|
//Split the aligned sequence into separate AARs
|
|
22
58
|
let splitSeqDf: DG.DataFrame | undefined;
|
|
23
59
|
let invalidIndexes: number[];
|
|
@@ -50,6 +86,7 @@ export async function describe(
|
|
|
50
86
|
setAARRenderer(col, sourceGrid);
|
|
51
87
|
}
|
|
52
88
|
}
|
|
89
|
+
|
|
53
90
|
if (sourceGrid) {
|
|
54
91
|
const colNames:string[] = [];
|
|
55
92
|
for (let i = 0; i < sourceGrid.columns.length; i++) {
|
|
@@ -105,6 +142,17 @@ export async function describe(
|
|
|
105
142
|
|
|
106
143
|
let matrixDf = splitSeqDf.unpivot([activityColumnScaled], positionColumns, positionColName, aminoAcidResidue);
|
|
107
144
|
|
|
145
|
+
//TODO: move to chem palette
|
|
146
|
+
let groupMapping: {[key: string]: string} = {};
|
|
147
|
+
if (grouping) {
|
|
148
|
+
groupMapping = aarGroups;
|
|
149
|
+
const aarCol = matrixDf.getCol(aminoAcidResidue);
|
|
150
|
+
aarCol.init((index) => groupMapping[aarCol.get(index)[0]] ?? '-');
|
|
151
|
+
aarCol.compact();
|
|
152
|
+
} else {
|
|
153
|
+
Object.keys(aarGroups).forEach((value) => groupMapping[value] = value);
|
|
154
|
+
}
|
|
155
|
+
|
|
108
156
|
//statistics for specific AAR at a specific position
|
|
109
157
|
matrixDf = matrixDf.groupBy([positionColName, aminoAcidResidue])
|
|
110
158
|
.add('count', activityColumnScaled, 'Count')
|
|
@@ -135,14 +183,14 @@ export async function describe(
|
|
|
135
183
|
AAR = matrixDf.get(aminoAcidResidue, i);
|
|
136
184
|
|
|
137
185
|
//@ts-ignore
|
|
138
|
-
splitSeqDf.rows.select((row) => row[position] === AAR);
|
|
186
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] === AAR);
|
|
139
187
|
currentActivity = splitSeqDf
|
|
140
188
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
141
189
|
.getCol(activityColumnScaled)
|
|
142
190
|
.toList();
|
|
143
191
|
|
|
144
192
|
//@ts-ignore
|
|
145
|
-
splitSeqDf.rows.select((row) => row[position] !== AAR);
|
|
193
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] !== AAR);
|
|
146
194
|
otherActivity = splitSeqDf
|
|
147
195
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
148
196
|
.getCol(activityColumnScaled)
|
|
@@ -190,11 +238,9 @@ export async function describe(
|
|
|
190
238
|
aarList.sort((first, second) => getWeight(second) - getWeight(first));
|
|
191
239
|
|
|
192
240
|
matrixDf.getCol(aminoAcidResidue).setCategoryOrder(aarList);
|
|
193
|
-
//const sequenceDf = segregateBestAtAllCateg(statsDf, twoColorMode);
|
|
194
241
|
|
|
195
242
|
// SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
|
|
196
243
|
// TODO: aquire ALL of the positions
|
|
197
|
-
|
|
198
244
|
let sequenceDf = statsDf.groupBy(['Mean difference', aminoAcidResidue, positionColName, 'Count', 'Ratio', 'pValue'])
|
|
199
245
|
.where('pValue <= 0.1')
|
|
200
246
|
.aggregate();
|
|
@@ -224,17 +270,14 @@ export async function describe(
|
|
|
224
270
|
SARVgrid.col('pValue')!.format = 'four digits after comma';
|
|
225
271
|
SARVgrid.col('pValue')!.name = 'P-Value';
|
|
226
272
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
setAARRenderer(
|
|
231
|
-
break;
|
|
273
|
+
if (!grouping) {
|
|
274
|
+
let tempCol = matrixDf.columns.byName(aminoAcidResidue);
|
|
275
|
+
if (tempCol) {
|
|
276
|
+
setAARRenderer(tempCol, SARgrid);
|
|
232
277
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
setAARRenderer(col, SARVgrid);
|
|
237
|
-
break;
|
|
278
|
+
tempCol = sequenceDf.columns.byName(aminoAcidResidue);
|
|
279
|
+
if (tempCol) {
|
|
280
|
+
setAARRenderer(tempCol, SARgrid);
|
|
238
281
|
}
|
|
239
282
|
}
|
|
240
283
|
|
|
@@ -251,19 +294,6 @@ export async function describe(
|
|
|
251
294
|
return;
|
|
252
295
|
}
|
|
253
296
|
|
|
254
|
-
// if (args.cell.isColHeader) {
|
|
255
|
-
// if (args.cell.gridColumn.name != aminoAcidResidue) {
|
|
256
|
-
// const textSize = args.g.measureText(args.cell.gridColumn.name);
|
|
257
|
-
// args.g.fillStyle = '#4b4b4a';
|
|
258
|
-
// args.g.fillText(
|
|
259
|
-
// args.cell.gridColumn.name,
|
|
260
|
-
// args.bounds.x + (args.bounds.width - textSize.width) / 2,
|
|
261
|
-
// args.bounds.y + (textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent),
|
|
262
|
-
// );
|
|
263
|
-
// }
|
|
264
|
-
// args.preventDefault();
|
|
265
|
-
// }
|
|
266
|
-
|
|
267
297
|
if (
|
|
268
298
|
args.cell.isTableCell &&
|
|
269
299
|
args.cell.tableRowIndex !== null &&
|
|
@@ -357,12 +387,18 @@ export async function describe(
|
|
|
357
387
|
}
|
|
358
388
|
if (
|
|
359
389
|
!cell.isColHeader &&
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
390
|
+
cell.tableColumn !== null &&
|
|
391
|
+
cell.tableColumn.name == aminoAcidResidue &&
|
|
392
|
+
cell.cell.value !== null &&
|
|
393
|
+
cell.tableRowIndex !== null
|
|
364
394
|
) {
|
|
365
|
-
|
|
395
|
+
if (grouping) {
|
|
396
|
+
const currentGroup = groupDescription[cell.cell.value];
|
|
397
|
+
const divText = ui.divText('Amino Acids in this group: ' + currentGroup['aminoAcids'].join(', '));
|
|
398
|
+
ui.tooltip.show(ui.divV([ui.h3(currentGroup['description']), divText]), x, y);
|
|
399
|
+
} else {
|
|
400
|
+
cp.showTooltip(cell, x, y);
|
|
401
|
+
}
|
|
366
402
|
}
|
|
367
403
|
return true;
|
|
368
404
|
};
|
|
@@ -376,9 +412,14 @@ export async function describe(
|
|
|
376
412
|
}
|
|
377
413
|
});
|
|
378
414
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
415
|
+
for (const col of matrixDf.columns.names()) {
|
|
416
|
+
SARgrid.col(col)!.width = SARgrid.props.rowHeight;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (grouping) {
|
|
420
|
+
SARgrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
421
|
+
SARVgrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
422
|
+
}
|
|
382
423
|
|
|
383
|
-
return [SARgrid, SARVgrid, statsDf];
|
|
424
|
+
return [SARgrid, SARVgrid, statsDf, groupMapping];
|
|
384
425
|
}
|
package/src/package.ts
CHANGED
|
@@ -14,7 +14,8 @@ import {analyzePeptidesWidget} from './widgets/analyze-peptides';
|
|
|
14
14
|
import {PeptideSimilaritySpaceWidget} from './utils/peptide-similarity-space';
|
|
15
15
|
import {manualAlignmentWidget} from './widgets/manual-alignment';
|
|
16
16
|
import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
|
|
17
|
-
import {
|
|
17
|
+
import {peptideMoleculeWidget} from './widgets/peptide-molecule';
|
|
18
|
+
import {correlationAnalysisPlots} from './utils/correlation-analysis';
|
|
18
19
|
|
|
19
20
|
export const _package = new DG.Package();
|
|
20
21
|
let tableGrid: DG.Grid;
|
|
@@ -24,35 +25,13 @@ let view: DG.TableView;
|
|
|
24
25
|
|
|
25
26
|
async function main(chosenFile: string) {
|
|
26
27
|
const pi = DG.TaskBarProgressIndicator.create('Loading Peptides');
|
|
27
|
-
//let peptides =
|
|
28
|
-
// await grok.data.loadTable('https://datagrok.jnj.com/p/ejaeger.il23peptideidp5562/il-23_peptide_idp-5562');
|
|
29
28
|
const path = _package.webRoot + 'files/' + chosenFile;
|
|
30
29
|
const peptides = (await grok.data.loadTable(path));
|
|
31
30
|
peptides.name = 'Peptides';
|
|
32
31
|
peptides.setTag('dataType', 'peptides');
|
|
33
32
|
const view = grok.shell.addTableView(peptides);
|
|
34
33
|
tableGrid = view.grid;
|
|
35
|
-
// peptides.onSemanticTypeDetecting.subscribe((_: any) => {
|
|
36
|
-
// const regexp = new RegExp(/^([^-^\n]*-){2,49}(\w|\(|\))+$/);
|
|
37
|
-
// for (const col of peptides.columns) {
|
|
38
|
-
// col.semType = DG.Detector.sampleCategories(col, (s: any) => regexp.test(s.trim())) ? 'alignedSequence' : null;
|
|
39
|
-
// if (col.semType == 'alignedSequence') {
|
|
40
|
-
// expandColumn(col, tableGrid, (ent)=>{
|
|
41
|
-
// const subParts:string[] = ent.split('-');
|
|
42
|
-
// // eslint-disable-next-line no-unused-vars
|
|
43
|
-
// const [text, _] = processSequence(subParts);
|
|
44
|
-
// let textSize = 0;
|
|
45
|
-
// text.forEach((aar)=>{
|
|
46
|
-
// textSize += aar.length;
|
|
47
|
-
// });
|
|
48
|
-
// return textSize;
|
|
49
|
-
// });
|
|
50
|
-
// }
|
|
51
|
-
// }
|
|
52
|
-
// });
|
|
53
|
-
|
|
54
34
|
view.name = 'PeptidesView';
|
|
55
|
-
|
|
56
35
|
grok.shell.windows.showProperties = true;
|
|
57
36
|
|
|
58
37
|
pi.close();
|
|
@@ -66,7 +45,6 @@ export function Peptides() {
|
|
|
66
45
|
|
|
67
46
|
const appDescription = ui.info(
|
|
68
47
|
[
|
|
69
|
-
// ui.divText('\n To start the application :', {style: {'font-weight': 'bolder'}}),
|
|
70
48
|
ui.list([
|
|
71
49
|
'- automatic recognition of peptide sequences',
|
|
72
50
|
'- native integration with tons of Datagrok out-of-the box features (visualization, filtering, clustering, ' +
|
|
@@ -196,6 +174,18 @@ export function manualAlignment(monomer: string) {
|
|
|
196
174
|
//input: column col {semType: alignedSequence}
|
|
197
175
|
//output: widget result
|
|
198
176
|
export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
|
|
199
|
-
const widget = new PeptideSimilaritySpaceWidget(col);
|
|
177
|
+
const widget = new PeptideSimilaritySpaceWidget(col, view ?? grok.shell.v);
|
|
200
178
|
return await widget.draw();
|
|
201
179
|
}
|
|
180
|
+
|
|
181
|
+
//name: Correllation analysis
|
|
182
|
+
export async function correlationAnalysis() {
|
|
183
|
+
view = (grok.shell.v as DG.TableView);
|
|
184
|
+
|
|
185
|
+
const df = await grok.data.files.openTable('Demo:TestJobs:Files:DemoFiles/bio/peptides.csv');
|
|
186
|
+
const tview = grok.shell.addTableView(df);
|
|
187
|
+
const [cpviewer, bpviewer] = correlationAnalysisPlots(df.getCol('AlignedSequence'));
|
|
188
|
+
|
|
189
|
+
tview.dockManager.dock(cpviewer, 'right');
|
|
190
|
+
tview.dockManager.dock(bpviewer, 'down');
|
|
191
|
+
}
|
package/src/peptides.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import {createPeptideSimilaritySpaceViewer} from './utils/peptide-similarity-space';
|
|
4
|
+
import {addViewerToHeader} from './viewers/stacked-barchart-viewer';
|
|
5
|
+
|
|
6
|
+
export class Peptides {
|
|
7
|
+
async init(
|
|
8
|
+
tableGrid: DG.Grid,
|
|
9
|
+
view: DG.TableView,
|
|
10
|
+
currentDf: DG.DataFrame,
|
|
11
|
+
options: {[key: string]: string},
|
|
12
|
+
col: DG.Column,
|
|
13
|
+
activityColumnChoice: string,
|
|
14
|
+
) {
|
|
15
|
+
for (let i = 0; i < tableGrid.columns.length; i++) {
|
|
16
|
+
const col = tableGrid.columns.byIndex(i);
|
|
17
|
+
if (col &&
|
|
18
|
+
col.name &&
|
|
19
|
+
col.column?.semType != 'aminoAcids'
|
|
20
|
+
) {
|
|
21
|
+
//@ts-ignore
|
|
22
|
+
tableGrid.columns.byIndex(i)?.visible = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
|
|
27
|
+
|
|
28
|
+
const sarViewer = view.addViewer('peptide-sar-viewer', options);
|
|
29
|
+
const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
|
|
30
|
+
|
|
31
|
+
const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
|
|
32
|
+
view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
|
|
33
|
+
|
|
34
|
+
const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
|
|
35
|
+
currentDf,
|
|
36
|
+
col,
|
|
37
|
+
't-SNE',
|
|
38
|
+
'Levenshtein',
|
|
39
|
+
100,
|
|
40
|
+
view,
|
|
41
|
+
`${activityColumnChoice}Scaled`,
|
|
42
|
+
);
|
|
43
|
+
view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
|
|
44
|
+
|
|
45
|
+
const StackedBarchartProm = currentDf.plot.fromType('StackedBarChartAA');
|
|
46
|
+
addViewerToHeader(tableGrid, StackedBarchartProm);
|
|
47
|
+
|
|
48
|
+
const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
|
|
49
|
+
const viewers = [];
|
|
50
|
+
for (const viewer of view.viewers) {
|
|
51
|
+
if (viewer.type !== DG.VIEWER.GRID) {
|
|
52
|
+
viewers.push(viewer);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
viewers.forEach((v) => v.close());
|
|
56
|
+
|
|
57
|
+
const cols = (currentDf.columns as DG.ColumnList);
|
|
58
|
+
for (const colName of cols.names()) {
|
|
59
|
+
if (!originalDfColumns.includes(colName)) {
|
|
60
|
+
cols.remove(colName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
currentDf.selection.setAll(false);
|
|
65
|
+
currentDf.filter.setAll(true);
|
|
66
|
+
|
|
67
|
+
tableGrid.setOptions({'colHeaderHeight': 20});
|
|
68
|
+
tableGrid.columns.setVisible(originalDfColumns);
|
|
69
|
+
|
|
70
|
+
view.setRibbonPanels(ribbonPanels);
|
|
71
|
+
}, 'Close viewers and restore dataframe');
|
|
72
|
+
|
|
73
|
+
const ribbonPanels = view.getRibbonPanels();
|
|
74
|
+
view.setRibbonPanels([[hideIcon]]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -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])];
|
|
@@ -24,15 +23,19 @@ export class ChemPalette {
|
|
|
24
23
|
if (s in ChemPalette.AAFullNames) {
|
|
25
24
|
toDisplay = [ui.divText(ChemPalette.AANames[ChemPalette.AAFullNames[s]])];
|
|
26
25
|
}
|
|
27
|
-
const
|
|
26
|
+
const options = {
|
|
27
|
+
autoCrop: true,
|
|
28
|
+
autoCropMargin: 0,
|
|
29
|
+
suppressChiralText: true,
|
|
30
|
+
};
|
|
31
|
+
const sketch = grok.chem.svgMol(ChemPalette.AASmiles[aar], undefined, undefined, options);
|
|
28
32
|
toDisplay.push(sketch);
|
|
29
33
|
}
|
|
30
34
|
ui.tooltip.show(ui.divV(toDisplay), x, y);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
getColor( c: string) {
|
|
34
|
-
|
|
35
|
-
const [color, _] = this.getColorPivot(c);
|
|
38
|
+
const [color] = this.getColorPivot(c);
|
|
36
39
|
return color;
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -77,8 +80,7 @@ export class ChemPalette {
|
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
getColorPivot(c = ''): [string, number] {
|
|
80
|
-
|
|
81
|
-
const [color, _, pivot] = this.getColorAAPivot(c);
|
|
83
|
+
const [color,, pivot] = this.getColorAAPivot(c);
|
|
82
84
|
return [color, pivot];
|
|
83
85
|
};
|
|
84
86
|
|
|
@@ -105,14 +107,6 @@ export class ChemPalette {
|
|
|
105
107
|
'white': ['rgb(230,230,230)'],
|
|
106
108
|
}
|
|
107
109
|
|
|
108
|
-
// static grokGroups: [string[], string][] = [
|
|
109
|
-
// [['C', 'U'], 'yellow'],
|
|
110
|
-
// [['G', 'P'], 'red'],
|
|
111
|
-
// [['A', 'V', 'I', 'L', 'M', 'F', 'Y', 'W'], 'all_green'],
|
|
112
|
-
// [['R', 'H', 'K'], 'light_blue'],
|
|
113
|
-
// [['D', 'E'], 'dark_blue'],
|
|
114
|
-
// [['S', 'T', 'N', 'Q'], 'orange'],
|
|
115
|
-
// ];
|
|
116
110
|
static grokGroups: {[key: string]: string[]} = {
|
|
117
111
|
'yellow': ['C', 'U'],
|
|
118
112
|
'red': ['G', 'P'],
|
|
@@ -130,14 +124,17 @@ export class ChemPalette {
|
|
|
130
124
|
'all_blue': ['K', 'R'],
|
|
131
125
|
}
|
|
132
126
|
|
|
133
|
-
static undefinedColor = 'rgb(100,100,100)'
|
|
127
|
+
static undefinedColor = 'rgb(100,100,100)';
|
|
134
128
|
|
|
135
|
-
static makePalette(dt: {[key: string]: string[]}, simplified = false) {
|
|
129
|
+
static makePalette(dt: {[key: string]: string[]}, simplified = false, grouping = false) {
|
|
136
130
|
const palette: { [key: string]: string } = {};
|
|
131
|
+
const groups = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
132
|
+
let currentGroup = 0;
|
|
137
133
|
for (const [color, monomers] of Object.entries(dt)) {
|
|
138
134
|
monomers.forEach((monomer, index) => {
|
|
139
|
-
palette[monomer] = ChemPalette.colourPalette[color][simplified ? 0 : index];
|
|
135
|
+
palette[grouping ? groups[currentGroup] : monomer] = ChemPalette.colourPalette[color][simplified ? 0 : index];
|
|
140
136
|
});
|
|
137
|
+
currentGroup++;
|
|
141
138
|
}
|
|
142
139
|
return palette;
|
|
143
140
|
}
|
|
@@ -234,8 +231,8 @@ export class ChemPalette {
|
|
|
234
231
|
'Val': 'V',
|
|
235
232
|
}
|
|
236
233
|
|
|
237
|
-
static getDatagrok() {
|
|
238
|
-
return ChemPalette.makePalette(ChemPalette.grokGroups);
|
|
234
|
+
static getDatagrok(grouping = false) {
|
|
235
|
+
return ChemPalette.makePalette(ChemPalette.grokGroups, false, grouping);
|
|
239
236
|
}
|
|
240
237
|
|
|
241
238
|
static getLesk() {
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* Do not change these import lines. Datagrok will import API library in exactly the same manner */
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
|
|
4
|
+
import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
|
|
5
|
+
import {assert, transposeMatrix} from '@datagrok-libraries/utils/src/operations';
|
|
6
|
+
import {Vector, Matrix} from '@datagrok-libraries/utils/src/type-declarations';
|
|
7
|
+
import {kendallsTau} from '@datagrok-libraries/statistics/src/correlation-coefficient';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Converts a Matrix into a DataFrame.
|
|
11
|
+
*
|
|
12
|
+
* @export
|
|
13
|
+
* @param {Matrix} matrix A matrix.
|
|
14
|
+
* @return {DG.DataFrame} The data frame.
|
|
15
|
+
*/
|
|
16
|
+
export function matrix2DataFrame(matrix: Matrix): DG.DataFrame {
|
|
17
|
+
return DG.DataFrame.fromColumns(matrix.map((v, i) => DG.Column.fromFloat32Array(`${i+1}`, v)));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Encodes amino acid sequences into a numeric representation.
|
|
22
|
+
*
|
|
23
|
+
* @param {DG.Column} col A column containing the sequences.
|
|
24
|
+
* @return {DG.DataFrame} The resulting data frame.
|
|
25
|
+
*/
|
|
26
|
+
function calcPositions(col: DG.Column): DG.DataFrame {
|
|
27
|
+
const sequences = col.toList().map((v, _) => AlignedSequenceEncoder.clean(v));
|
|
28
|
+
const enc = new AlignedSequenceEncoder();
|
|
29
|
+
const encSeqs = sequences.map((v) => Vector.from(enc.encode(v)));
|
|
30
|
+
const positions = transposeMatrix(encSeqs);
|
|
31
|
+
return matrix2DataFrame(positions);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Unfolds a data frame into <category>-<value> format.
|
|
36
|
+
*
|
|
37
|
+
* @param {DG.DataFrame} df A data frame to unfold.
|
|
38
|
+
* @return {DG.DataFrame} The resulting data frame.
|
|
39
|
+
*/
|
|
40
|
+
function melt(df: DG.DataFrame): DG.DataFrame {
|
|
41
|
+
let keys: string[] = [];
|
|
42
|
+
const values: Float32Array = new Float32Array(df.columns.length*df.rowCount);
|
|
43
|
+
let i = 0;
|
|
44
|
+
|
|
45
|
+
for (const c of df.columns.toList()) {
|
|
46
|
+
keys = keys.concat(Array<string>(c.length).fill(c.name));
|
|
47
|
+
values.set(c.getRawData(), i);
|
|
48
|
+
i += df.rowCount;
|
|
49
|
+
}
|
|
50
|
+
assert(keys.length == values.length);
|
|
51
|
+
return DG.DataFrame.fromColumns([DG.Column.fromStrings('keys', keys), DG.Column.fromFloat32Array('values', values)]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Calculates Spearman's rho rank correlation coefficient.
|
|
56
|
+
*
|
|
57
|
+
* @param {DG.DataFrame} df A data frame to process.
|
|
58
|
+
* @return {DG.DataFrame} The correlation matrix.
|
|
59
|
+
*/
|
|
60
|
+
function calcSpearmanRhoMatrix(df: DG.DataFrame): DG.DataFrame {
|
|
61
|
+
const nItems = df.columns.length;
|
|
62
|
+
const rho = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
|
|
63
|
+
|
|
64
|
+
for (let i = 0; i < nItems; ++i) {
|
|
65
|
+
for (let j = i+1; j < nItems; ++j) {
|
|
66
|
+
rho[i][j] = df.columns.byIndex(i).stats.spearmanCorr(df.columns.byIndex(j));
|
|
67
|
+
rho[j][i] = rho[i][j];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return matrix2DataFrame(rho);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Calculates Kendall's tau rank correlation coefficient.
|
|
75
|
+
*
|
|
76
|
+
* @param {DG.DataFrame} df A data frame to process.
|
|
77
|
+
* @param {number} [alpha=0.05] The significance threshold.
|
|
78
|
+
* @return {DG.DataFrame} The correlation matrix.
|
|
79
|
+
*/
|
|
80
|
+
function calcKendallTauMatrix(df: DG.DataFrame, alpha: number = 0.05): DG.DataFrame {
|
|
81
|
+
const nItems = df.columns.length;
|
|
82
|
+
const tau = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < nItems; ++i) {
|
|
85
|
+
for (let j = i+1; j < nItems; ++j) {
|
|
86
|
+
const res = kendallsTau(df.columns.byIndex(i).getRawData(), df.columns.byIndex(j).getRawData());
|
|
87
|
+
tau[i][j] = res.prob < alpha ? res.test : 0;
|
|
88
|
+
tau[j][i] = tau[i][j];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return matrix2DataFrame(tau);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates acorrelation plot and a box plot to perform correlation analysis.
|
|
96
|
+
*
|
|
97
|
+
* @export
|
|
98
|
+
* @param {DG.Column} sequencesColumn A column containing amino acid sequences.
|
|
99
|
+
* @return {[DG.Viewer, DG.Viewer]} These two plots.
|
|
100
|
+
*/
|
|
101
|
+
export function correlationAnalysisPlots(sequencesColumn: DG.Column): [DG.Viewer, DG.Viewer] {
|
|
102
|
+
const posDF = calcPositions(sequencesColumn);
|
|
103
|
+
const cpviewer = DG.Viewer.fromType(
|
|
104
|
+
DG.VIEWER.CORR_PLOT,
|
|
105
|
+
posDF,
|
|
106
|
+
{
|
|
107
|
+
'xColumnNames': posDF.columns.names(),
|
|
108
|
+
'yColumnNames': posDF.columns.names(),
|
|
109
|
+
'correlationType': 'Spearman',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const rhoDF = calcKendallTauMatrix(posDF);
|
|
113
|
+
const meltDF = melt(rhoDF);
|
|
114
|
+
|
|
115
|
+
const bpviewer = DG.Viewer.fromType(
|
|
116
|
+
DG.VIEWER.BOX_PLOT,
|
|
117
|
+
meltDF, {
|
|
118
|
+
'categoryColumnName': 'keys',
|
|
119
|
+
'valueColumnName': 'values',
|
|
120
|
+
'statistics': ['min', 'max', 'avg', 'med'],
|
|
121
|
+
});
|
|
122
|
+
return [cpviewer, bpviewer];
|
|
123
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/* Do not change these import lines. Datagrok will import API library in exactly the same manner */
|
|
2
|
-
// eslint-disable-next-line no-unused-vars
|
|
3
|
-
import * as grok from 'datagrok-api/grok';
|
|
4
2
|
import * as ui from 'datagrok-api/ui';
|
|
5
3
|
import * as DG from 'datagrok-api/dg';
|
|
6
4
|
|
|
@@ -8,17 +6,8 @@ import {getSequenceMolecularWeight} from './molecular-measure';
|
|
|
8
6
|
import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
|
|
9
7
|
import {DimensionalityReducer} from '@datagrok-libraries/utils/src/reduce-dimensionality';
|
|
10
8
|
import {Measurer} from '@datagrok-libraries/utils/src/string-measure';
|
|
11
|
-
import {Coordinates} from '@datagrok-libraries/utils/src/
|
|
9
|
+
import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
* Creates a worker to perform a dimensionality reduction.
|
|
15
|
-
*
|
|
16
|
-
* @param {any[]} columnData Samples to process.
|
|
17
|
-
* @param {string} method Embedding method.
|
|
18
|
-
* @param {string} measure Distance metric.
|
|
19
|
-
* @param {number} cyclesCount Number of cycles to repeat.
|
|
20
|
-
* @return {Promise<unknown>} Promise.
|
|
21
|
-
*/
|
|
22
11
|
function createDimensinalityReducingWorker(
|
|
23
12
|
columnData: any[],
|
|
24
13
|
method: string,
|
|
@@ -65,6 +54,7 @@ function inferActivityColumnsName(table: DG.DataFrame): string | null {
|
|
|
65
54
|
* @param {string} method Embedding method to apply.
|
|
66
55
|
* @param {string} measure Distance metric.
|
|
67
56
|
* @param {number} cyclesCount Number of cycles to repeat.
|
|
57
|
+
* @param {(DG.TableView | null)} view View to add scatter plot to
|
|
68
58
|
* @param {(string | null)} [activityColumnName] Activity containing column to assign it to points radius.
|
|
69
59
|
* @param {boolean} [zoom=false] Whether to fit view.
|
|
70
60
|
* @return {Promise<DG.ScatterPlotViewer>} A viewer.
|
|
@@ -75,6 +65,7 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
75
65
|
method: string,
|
|
76
66
|
measure: string,
|
|
77
67
|
cyclesCount: number,
|
|
68
|
+
view: DG.TableView | null,
|
|
78
69
|
activityColumnName?: string | null,
|
|
79
70
|
zoom: boolean = false,
|
|
80
71
|
): Promise<DG.ScatterPlotViewer> {
|
|
@@ -117,8 +108,11 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
117
108
|
table.columns.replace(col, edf.getCol(axis));
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
|
-
const viewer = DG.Viewer.scatterPlot(table, {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'});
|
|
121
111
|
|
|
112
|
+
// const viewer = DG.Viewer.scatterPlot(table, {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'});
|
|
113
|
+
const viewerOptions = {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'};
|
|
114
|
+
const viewer = view !== null ?
|
|
115
|
+
view.addViewer(DG.VIEWER.SCATTER_PLOT, viewerOptions) : DG.Viewer.scatterPlot(table, viewerOptions);
|
|
122
116
|
// Fit view if needed.
|
|
123
117
|
/*if (zoom) {
|
|
124
118
|
viewer.zoom(
|
|
@@ -129,7 +123,7 @@ export async function createPeptideSimilaritySpaceViewer(
|
|
|
129
123
|
);
|
|
130
124
|
}*/
|
|
131
125
|
pi.close();
|
|
132
|
-
return viewer;
|
|
126
|
+
return (viewer as DG.ScatterPlotViewer);
|
|
133
127
|
}
|
|
134
128
|
|
|
135
129
|
/**
|
|
@@ -147,13 +141,15 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
147
141
|
protected availableMethods: string[];
|
|
148
142
|
protected availableMetrics: string[];
|
|
149
143
|
protected viewer: HTMLElement;
|
|
144
|
+
view: DG.TableView;
|
|
150
145
|
|
|
151
146
|
/**
|
|
152
147
|
* Creates an instance of PeptideSimilaritySpaceWidget.
|
|
153
148
|
* @param {DG.Column} alignedSequencesColumn The column to get amino acid sequences from.
|
|
149
|
+
* @param {DG.TableView} view Current view
|
|
154
150
|
* @memberof PeptideSimilaritySpaceWidget
|
|
155
151
|
*/
|
|
156
|
-
constructor(alignedSequencesColumn: DG.Column) {
|
|
152
|
+
constructor(alignedSequencesColumn: DG.Column, view: DG.TableView) {
|
|
157
153
|
this.availableMethods = DimensionalityReducer.availableMethods;
|
|
158
154
|
this.availableMetrics = Measurer.availableMeasures;
|
|
159
155
|
this.method = this.availableMethods[0];
|
|
@@ -161,6 +157,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
161
157
|
this.currentDf = alignedSequencesColumn.dataFrame;
|
|
162
158
|
this.alignedSequencesColumn = alignedSequencesColumn;
|
|
163
159
|
this.viewer = ui.div([]);
|
|
160
|
+
this.view = view;
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
/**
|
|
@@ -177,6 +174,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
177
174
|
this.metrics,
|
|
178
175
|
this.cycles,
|
|
179
176
|
null,
|
|
177
|
+
null,
|
|
180
178
|
true,
|
|
181
179
|
);
|
|
182
180
|
viewer.root.style.width = 'auto';
|
|
@@ -45,7 +45,6 @@ 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
|
-
|
|
49
48
|
if (filter) {
|
|
50
49
|
splitColumns = splitColumns.filter((positionArray, index) => {
|
|
51
50
|
const isRetained = new Set(positionArray).size > 1;
|
|
@@ -61,7 +61,6 @@ export class Logo extends DG.JsViewer {
|
|
|
61
61
|
|
|
62
62
|
init() {
|
|
63
63
|
this.initialized = true;
|
|
64
|
-
// this.reactHost = ui.div([]);
|
|
65
64
|
console.log('INIT');
|
|
66
65
|
this.target = this.dataFrame;
|
|
67
66
|
[this.splitted] = splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
|
|
@@ -111,10 +110,6 @@ export class Logo extends DG.JsViewer {
|
|
|
111
110
|
|
|
112
111
|
if (typeof this.dataFrame !== 'undefined') {
|
|
113
112
|
this.findLogo();
|
|
114
|
-
|
|
115
|
-
// if (this.reactHost !== null) {
|
|
116
|
-
// this.root.appendChild(this.reactHost);
|
|
117
|
-
// }
|
|
118
113
|
}
|
|
119
114
|
}
|
|
120
115
|
|
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,18 @@ 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
|
-
|
|
23
|
+
grouping: boolean;
|
|
24
|
+
groupMapping: {[key: string]: string} | null;
|
|
24
25
|
// protected pValueThreshold: number;
|
|
25
26
|
// protected amountOfBestAARs: number;
|
|
26
27
|
// duplicatesHandingMethod: string;
|
|
27
28
|
constructor() {
|
|
28
29
|
super();
|
|
29
|
-
|
|
30
|
+
|
|
30
31
|
this.viewerGrid = null;
|
|
31
32
|
this.viewerVGrid = null;
|
|
32
33
|
this.statsDf = null;
|
|
34
|
+
this.groupMapping = null;
|
|
33
35
|
this.initialized = false;
|
|
34
36
|
this.aminoAcidResidue = 'AAR';
|
|
35
37
|
this._initialBitset = null;
|
|
@@ -41,6 +43,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
41
43
|
this.activityScalingMethod = this.string('activityScalingMethod', 'none', {choices: ['none', 'lg', '-lg']});
|
|
42
44
|
this.filterMode = this.bool('filterMode', false);
|
|
43
45
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
46
|
+
this.grouping = this.bool('grouping', false);
|
|
44
47
|
// this.pValueThreshold = this.float('pValueThreshold', 0.1);
|
|
45
48
|
// this.amountOfBestAARs = this.int('amountOfBestAAR', 1);
|
|
46
49
|
// this.duplicatesHandingMethod = this.string('duplicatesHandlingMethod', 'median', {choices: ['median']});
|
|
@@ -51,12 +54,13 @@ export class SARViewer extends DG.JsViewer {
|
|
|
51
54
|
init() {
|
|
52
55
|
this._initialBitset = this.dataFrame!.filter.clone();
|
|
53
56
|
this.initialized = true;
|
|
54
|
-
this.subs.push(model.statsDf$.subscribe(data => this.statsDf = data));
|
|
55
|
-
this.subs.push(model.viewerGrid$.subscribe(data => {
|
|
57
|
+
this.subs.push(model.statsDf$.subscribe((data) => this.statsDf = data));
|
|
58
|
+
this.subs.push(model.viewerGrid$.subscribe((data) => {
|
|
56
59
|
this.viewerGrid = data;
|
|
57
60
|
this.render();
|
|
58
61
|
}));
|
|
59
|
-
this.subs.push(model.viewerVGrid$.subscribe(data => this.viewerVGrid = data));
|
|
62
|
+
this.subs.push(model.viewerVGrid$.subscribe((data) => this.viewerVGrid = data));
|
|
63
|
+
this.subs.push(model.groupMapping$.subscribe((data) => this.groupMapping = data));
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
onTableAttached() {
|
|
@@ -114,25 +118,13 @@ export class SARViewer extends DG.JsViewer {
|
|
|
114
118
|
splitCol = this.dataFrame.columns.addNew(splitColName, 'string');
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
const isChosen = (i: number) => this.dataFrame!.get(currentPosition, i) === currentAAR;
|
|
121
|
+
const isChosen = (i: number) => this.groupMapping![this.dataFrame!.get(currentPosition, i)] === currentAAR;
|
|
118
122
|
splitCol!.init((i) => isChosen(i) ? aarLabel : otherLabel);
|
|
119
123
|
|
|
120
124
|
//TODO: use column.compact
|
|
121
|
-
|
|
122
|
-
// if (this.filterMode) {
|
|
123
|
-
// this.dataFrame.selection.setAll(false, false);
|
|
124
|
-
// this.dataFrame.filter.init(isChosen).and(this._initialBitset!, false);
|
|
125
|
-
// } else {
|
|
126
|
-
// this.dataFrame.filter.copyFrom(this._initialBitset!);
|
|
127
|
-
// this.dataFrame.selection.init(isChosen).and(this._initialBitset!, false);
|
|
128
|
-
// }
|
|
129
125
|
this.currentBitset = DG.BitSet.create(this.dataFrame.rowCount, isChosen).and(this._initialBitset!);
|
|
130
|
-
// (this.filterMode ? this.dataFrame.selection.setAll(false) :
|
|
131
|
-
// this.dataFrame.filter.copyFrom(this._initialBitset!)).fireChanged();
|
|
132
126
|
this.sourceFilteringFunc();
|
|
133
127
|
|
|
134
|
-
|
|
135
|
-
// df.getCol(splitColName).setCategoryOrder([otherLabel, aarLabel]);
|
|
136
128
|
const colorMap: {[index: string]: string | number} = {};
|
|
137
129
|
colorMap[otherLabel] = DG.Color.blue;
|
|
138
130
|
colorMap[aarLabel] = DG.Color.orange;
|
|
@@ -262,14 +254,6 @@ export class SARViewer extends DG.JsViewer {
|
|
|
262
254
|
//TODO: optimize. Don't calculate everything again if only view changes
|
|
263
255
|
if (computeData) {
|
|
264
256
|
if (typeof this.dataFrame !== 'undefined' && this.activityColumnColumnName && this.sourceGrid) {
|
|
265
|
-
// [this.viewerGrid, this.viewerVGrid, this.statsDf] = await describe(
|
|
266
|
-
// this.dataFrame,
|
|
267
|
-
// this.activityColumnColumnName,
|
|
268
|
-
// this.activityScalingMethod,
|
|
269
|
-
// this.sourceGrid,
|
|
270
|
-
// this.bidirectionalAnalysis,
|
|
271
|
-
// this._initialBitset,
|
|
272
|
-
// );
|
|
273
257
|
await model?.updateData(
|
|
274
258
|
this.dataFrame!,
|
|
275
259
|
this.activityColumnColumnName,
|
|
@@ -277,6 +261,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
277
261
|
this.sourceGrid,
|
|
278
262
|
this.bidirectionalAnalysis,
|
|
279
263
|
this._initialBitset,
|
|
264
|
+
this.grouping,
|
|
280
265
|
);
|
|
281
266
|
|
|
282
267
|
if (this.viewerGrid !== null && this.viewerVGrid !== null) {
|
|
@@ -303,7 +288,7 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
303
288
|
super();
|
|
304
289
|
|
|
305
290
|
this.viewerVGrid = null;
|
|
306
|
-
this.subs.push(model.viewerVGrid$.subscribe(data => {
|
|
291
|
+
this.subs.push(model.viewerVGrid$.subscribe((data) => {
|
|
307
292
|
this.viewerVGrid = data;
|
|
308
293
|
this.render();
|
|
309
294
|
}));
|
|
@@ -316,4 +301,4 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
316
301
|
}
|
|
317
302
|
this.viewerVGrid?.invalidate();
|
|
318
303
|
}
|
|
319
|
-
}
|
|
304
|
+
}
|
|
@@ -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();
|
|
@@ -287,8 +287,7 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
287
287
|
if (h * margin / 2 <= sBarHeight - gapSize && h * margin / 2 <= w) {
|
|
288
288
|
g.fillStyle = 'rgb(0,0,0)';
|
|
289
289
|
g.font = `${h * margin / 2}px`;
|
|
290
|
-
|
|
291
|
-
const [_c, aar, _p] = cp.getColorAAPivot(obj['name']);
|
|
290
|
+
const [, aar] = cp.getColorAAPivot(obj['name']);
|
|
292
291
|
g.fillText(aar,
|
|
293
292
|
x + w / 2 - h * margin / 8,
|
|
294
293
|
y + h * (this.max - sum + curSum) / this.max + gapSize / 2 + (sBarHeight - gapSize)/2 - h * margin / 8);
|
|
@@ -398,11 +397,8 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
398
397
|
return;
|
|
399
398
|
}
|
|
400
399
|
this.dataFrame!.selection.handleClick((i) => {
|
|
401
|
-
//let selected = true;
|
|
402
400
|
// @ts-ignore
|
|
403
401
|
return this.highlighted!['aaName'] === (this.dataFrame.getCol(this.highlighted!['colName']).get(i));
|
|
404
|
-
|
|
405
|
-
//&& (scope.dataFrame.selection.get(i) === selected);
|
|
406
402
|
}, event);
|
|
407
403
|
}
|
|
408
404
|
}
|
|
@@ -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
|
-
const
|
|
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
|
+
const 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.
|