@datagrok/peptides 0.8.5 → 0.8.6
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 +12 -2
- package/files/aligned.csv +648 -3
- package/files/aligned_2.csv +10275 -3
- package/package.json +2 -2
- package/setup.sh +15 -0
- package/src/describe.ts +41 -46
- package/src/monomer-library.ts +187 -0
- package/src/package.ts +25 -6
- package/src/peptides.ts +10 -5
- package/src/tests/peptides-tests.ts +52 -16
- package/src/tests/utils.ts +1 -2
- package/src/utils/cell-renderer.ts +27 -26
- package/src/utils/chem-palette.ts +5 -6
- package/src/utils/molecular-measure.ts +3 -4
- package/src/utils/multiple-sequence-alignment.ts +4 -4
- package/src/utils/peptide-similarity-space.ts +4 -6
- package/src/utils/split-aligned.ts +6 -6
- package/src/viewers/logo-viewer.ts +10 -12
- package/src/viewers/sar-viewer.ts +12 -14
- package/src/viewers/stacked-barchart-viewer.ts +21 -26
- package/src/viewers/subst-viewer.ts +10 -10
- package/src/widgets/analyze-peptides.ts +3 -4
- package/src/widgets/manual-alignment.ts +5 -3
- package/src/widgets/peptide-molecule.ts +4 -5
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@biowasm/aioli": ">=2.4.0",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@types/jquery": "^3.5.6",
|
|
13
13
|
"cash-dom": "latest",
|
|
14
14
|
"d3": "latest",
|
|
15
|
-
"datagrok-api": ">=0.
|
|
15
|
+
"datagrok-api": ">=0.115.0",
|
|
16
16
|
"dayjs": "latest",
|
|
17
17
|
"file-loader": "^6.2.0",
|
|
18
18
|
"jstat": "^1.9.5",
|
package/setup.sh
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
npm unlink datagrok-api
|
|
2
|
+
npm unlink @datagrok-libraries/utils
|
|
3
|
+
npm unlink @datagrok-libraries/ml
|
|
4
|
+
cd ../../js-api
|
|
5
|
+
npm install
|
|
6
|
+
npm link
|
|
7
|
+
cd ../libraries/utils
|
|
8
|
+
npm install
|
|
9
|
+
npm link
|
|
10
|
+
cd ../../libraries/ml
|
|
11
|
+
npm install
|
|
12
|
+
npm link datagrok-api @datagrok-libraries/utils
|
|
13
|
+
cd ../../packages/Peptides
|
|
14
|
+
npm install
|
|
15
|
+
npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/ml
|
package/src/describe.ts
CHANGED
|
@@ -60,41 +60,38 @@ function joinDataFrames(
|
|
|
60
60
|
splitSeqDf: DG.DataFrame,
|
|
61
61
|
activityColumn: string,
|
|
62
62
|
) {
|
|
63
|
-
if (df.col(activityColumnScaled))
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
if (df.col(activityColumnScaled))
|
|
64
|
+
(df.columns as DG.ColumnList).remove(activityColumnScaled);
|
|
65
|
+
|
|
66
66
|
|
|
67
67
|
//FIXME: this column usually duplicates, so remove it then
|
|
68
|
-
if (df.col(`${activityColumnScaled} (2)`))
|
|
69
|
-
df.columns.remove(`${activityColumnScaled} (2)`);
|
|
70
|
-
|
|
68
|
+
if (df.col(`${activityColumnScaled} (2)`))
|
|
69
|
+
(df.columns as DG.ColumnList).remove(`${activityColumnScaled} (2)`);
|
|
70
|
+
|
|
71
71
|
|
|
72
72
|
// append splitSeqDf columns to source table and make sure columns are not added more than once
|
|
73
73
|
const dfColsSet = new Set(df.columns.names());
|
|
74
|
-
if (!positionColumns.every((col: string) => dfColsSet.has(col)))
|
|
74
|
+
if (!positionColumns.every((col: string) => dfColsSet.has(col)))
|
|
75
75
|
df.join(splitSeqDf, [activityColumn], [activityColumn], df.columns.names(), positionColumns, 'inner', true);
|
|
76
|
-
}
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
function sortSourceGrid(sourceGrid: DG.Grid) {
|
|
80
79
|
if (sourceGrid) {
|
|
81
|
-
const colNames:
|
|
82
|
-
for (let i =
|
|
83
|
-
colNames.push(sourceGrid.columns.byIndex(i)
|
|
84
|
-
|
|
80
|
+
const colNames: DG.GridColumn[] = [];
|
|
81
|
+
for (let i = 1; i < sourceGrid.columns.length; i++)
|
|
82
|
+
colNames.push(sourceGrid.columns.byIndex(i)!);
|
|
83
|
+
|
|
85
84
|
colNames.sort((a, b)=>{
|
|
86
|
-
if (
|
|
87
|
-
if (
|
|
85
|
+
if (a.column!.semType == 'aminoAcids') {
|
|
86
|
+
if (b.column!.semType == 'aminoAcids')
|
|
88
87
|
return 0;
|
|
89
|
-
}
|
|
90
88
|
return -1;
|
|
91
89
|
}
|
|
92
|
-
if (
|
|
90
|
+
if (b.column!.semType == 'aminoAcids')
|
|
93
91
|
return 1;
|
|
94
|
-
}
|
|
95
92
|
return 0;
|
|
96
93
|
});
|
|
97
|
-
sourceGrid
|
|
94
|
+
sourceGrid.columns.setOrder(colNames.map((v) => v.name));
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
|
|
@@ -180,13 +177,13 @@ async function calculateStatistics(
|
|
|
180
177
|
pvalues[i] = pvalue;
|
|
181
178
|
}
|
|
182
179
|
|
|
183
|
-
if (true)
|
|
180
|
+
if (true)
|
|
184
181
|
pvalues = fdrcorrection(pvalues)[1];
|
|
185
|
-
}
|
|
186
182
|
|
|
187
|
-
|
|
183
|
+
|
|
184
|
+
for (let i = 0; i < pvalues.length; ++i)
|
|
188
185
|
pValCol.set(i, pvalues[i]);
|
|
189
|
-
|
|
186
|
+
|
|
190
187
|
|
|
191
188
|
return matrixDf.clone();
|
|
192
189
|
}
|
|
@@ -195,9 +192,9 @@ async function setCategoryOrder(
|
|
|
195
192
|
twoColorMode: boolean, statsDf: DG.DataFrame, aminoAcidResidue: string, matrixDf: DG.DataFrame,
|
|
196
193
|
) {
|
|
197
194
|
const sortArgument = twoColorMode ? 'Absolute Mean difference' : 'Mean difference';
|
|
198
|
-
if (twoColorMode)
|
|
195
|
+
if (twoColorMode)
|
|
199
196
|
await statsDf.columns.addNewCalculated('Absolute Mean difference', 'Abs(${Mean difference})');
|
|
200
|
-
|
|
197
|
+
|
|
201
198
|
const aarWeightsDf = statsDf.groupBy([aminoAcidResidue]).sum(sortArgument, 'weight').aggregate();
|
|
202
199
|
const aarList = aarWeightsDf.getCol(aminoAcidResidue).toList();
|
|
203
200
|
const getWeight = (aar: string) => aarWeightsDf
|
|
@@ -257,13 +254,12 @@ function createGrids(
|
|
|
257
254
|
|
|
258
255
|
if (!grouping) {
|
|
259
256
|
let tempCol = matrixDf.columns.byName(aminoAcidResidue);
|
|
260
|
-
if (tempCol)
|
|
257
|
+
if (tempCol)
|
|
261
258
|
setAARRenderer(tempCol, sarGrid);
|
|
262
|
-
|
|
259
|
+
|
|
263
260
|
tempCol = sequenceDf.columns.byName(aminoAcidResidue);
|
|
264
|
-
if (tempCol)
|
|
261
|
+
if (tempCol)
|
|
265
262
|
setAARRenderer(tempCol, sarGrid);
|
|
266
|
-
}
|
|
267
263
|
}
|
|
268
264
|
|
|
269
265
|
return [sarGrid, sarVGrid];
|
|
@@ -308,15 +304,15 @@ function setCellRendererFunc(
|
|
|
308
304
|
|
|
309
305
|
let coef;
|
|
310
306
|
const variant = args.cell.cell.value < 0;
|
|
311
|
-
if (pVal < 0.01)
|
|
307
|
+
if (pVal < 0.01)
|
|
312
308
|
coef = variant && twoColorMode ? '#FF7900' : '#299617';
|
|
313
|
-
|
|
309
|
+
else if (pVal < 0.05)
|
|
314
310
|
coef = variant && twoColorMode ? '#FFA500' : '#32CD32';
|
|
315
|
-
|
|
311
|
+
else if (pVal < 0.1)
|
|
316
312
|
coef = variant && twoColorMode ? '#FBCEB1' : '#98FF98';
|
|
317
|
-
|
|
313
|
+
else
|
|
318
314
|
coef = DG.Color.toHtml(DG.Color.lightLightGray);
|
|
319
|
-
|
|
315
|
+
|
|
320
316
|
|
|
321
317
|
const chooseMin = () => twoColorMode ? 0 : mdCol.min;
|
|
322
318
|
const chooseMax = () => twoColorMode ? Math.max(Math.abs(mdCol.min), mdCol.max) : mdCol.max;
|
|
@@ -380,11 +376,11 @@ function setTooltipFunc(
|
|
|
380
376
|
const textNum = statsDf.groupBy([col]).where(query).aggregate().get(col, 0);
|
|
381
377
|
let text = `${col === 'Count' ? textNum : textNum.toFixed(5)}`;
|
|
382
378
|
|
|
383
|
-
if (col === 'Count')
|
|
379
|
+
if (col === 'Count')
|
|
384
380
|
text += ` / ${peptidesCount}`;
|
|
385
|
-
|
|
381
|
+
else if (col === 'pValue')
|
|
386
382
|
text = parseFloat(text) !== 0 ? text : '<0.01';
|
|
387
|
-
|
|
383
|
+
|
|
388
384
|
|
|
389
385
|
tooltipMap[col === 'pValue' ? 'p-value' : col] = text;
|
|
390
386
|
}
|
|
@@ -403,9 +399,8 @@ function setTooltipFunc(
|
|
|
403
399
|
const currentGroup = groupDescription[cell.cell.value];
|
|
404
400
|
const divText = ui.divText('Amino Acids in this group: ' + currentGroup['aminoAcids'].join(', '));
|
|
405
401
|
ui.tooltip.show(ui.divV([ui.h3(currentGroup['description']), divText]), x, y);
|
|
406
|
-
} else
|
|
402
|
+
} else
|
|
407
403
|
cp.showTooltip(cell, x, y);
|
|
408
|
-
}
|
|
409
404
|
}
|
|
410
405
|
return true;
|
|
411
406
|
};
|
|
@@ -424,14 +419,13 @@ function postProcessGrids(
|
|
|
424
419
|
) {
|
|
425
420
|
sourceGrid.onCellPrepare((cell: DG.GridCell) => {
|
|
426
421
|
const currentRowIndex = cell.tableRowIndex;
|
|
427
|
-
if (currentRowIndex && invalidIndexes.includes(currentRowIndex) && !cell.isRowHeader)
|
|
422
|
+
if (currentRowIndex && invalidIndexes.includes(currentRowIndex) && !cell.isRowHeader)
|
|
428
423
|
cell.style.backColor = DG.Color.lightLightGray;
|
|
429
|
-
}
|
|
430
424
|
});
|
|
431
425
|
|
|
432
|
-
for (const col of matrixDf.columns.names())
|
|
426
|
+
for (const col of matrixDf.columns.names())
|
|
433
427
|
sarGrid.col(col)!.width = sarGrid.props.rowHeight;
|
|
434
|
-
|
|
428
|
+
|
|
435
429
|
|
|
436
430
|
if (grouping) {
|
|
437
431
|
sarGrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
@@ -440,6 +434,8 @@ function postProcessGrids(
|
|
|
440
434
|
|
|
441
435
|
sarGrid.props.allowEdit = false;
|
|
442
436
|
sarVGrid.props.allowEdit = false;
|
|
437
|
+
|
|
438
|
+
sarVGrid.col('Mean difference')!.name = 'Diff';
|
|
443
439
|
}
|
|
444
440
|
|
|
445
441
|
export async function describe(
|
|
@@ -469,9 +465,8 @@ export async function describe(
|
|
|
469
465
|
joinDataFrames(activityColumnScaled, df, positionColumns, splitSeqDf, activityColumn);
|
|
470
466
|
|
|
471
467
|
for (const col of df.columns) {
|
|
472
|
-
if (splitSeqDf.col(col.name) && col.name != activityColumn)
|
|
468
|
+
if (splitSeqDf.col(col.name) && col.name != activityColumn)
|
|
473
469
|
setAARRenderer(col, sourceGrid);
|
|
474
|
-
}
|
|
475
470
|
}
|
|
476
471
|
|
|
477
472
|
sortSourceGrid(sourceGrid);
|
|
@@ -495,9 +490,9 @@ export async function describe(
|
|
|
495
490
|
const aarCol = matrixDf.getCol(aminoAcidResidue);
|
|
496
491
|
aarCol.init((index) => groupMapping[aarCol.get(index)[0]] ?? '-');
|
|
497
492
|
aarCol.compact();
|
|
498
|
-
} else
|
|
493
|
+
} else
|
|
499
494
|
Object.keys(aarGroups).forEach((value) => groupMapping[value] = value);
|
|
500
|
-
|
|
495
|
+
|
|
501
496
|
|
|
502
497
|
//statistics for specific AAR at a specific position
|
|
503
498
|
const statsDf = await calculateStatistics(
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import * as grok from 'datagrok-api/grok';
|
|
4
|
+
|
|
5
|
+
/** HELM associated sdf libraries with monomer processing*/
|
|
6
|
+
export class MonomerLibrary {
|
|
7
|
+
private monomerFields: string[] = ['molecule', 'MonomerType', 'MonomerNaturalAnalogCode', 'MonomerName', 'MonomerCode', 'MonomerCaps', 'BranchMonomer'];
|
|
8
|
+
private library: {
|
|
9
|
+
[name: string]: {
|
|
10
|
+
mol: string,
|
|
11
|
+
type: string,
|
|
12
|
+
analogueCode: string,
|
|
13
|
+
linkages: { [link: string]: { atomNumber: number, type: string } }
|
|
14
|
+
}
|
|
15
|
+
} = {};
|
|
16
|
+
private monomers: string[] = [];
|
|
17
|
+
|
|
18
|
+
constructor(sdf: string) {
|
|
19
|
+
//sdf = sdf.replaceAll('\n\[', '\[');
|
|
20
|
+
const sdfReader = new SDFReader();
|
|
21
|
+
const data = sdfReader.get_colls(sdf);
|
|
22
|
+
this.monomerFields.forEach((f) => {
|
|
23
|
+
if (!(f in data))
|
|
24
|
+
throw `Monomer library was not compiled: ${f} field is absent in provided file`;
|
|
25
|
+
|
|
26
|
+
if (data[f].length != data.molecule.length)
|
|
27
|
+
throw `Monomer library was not compiled: ${f} field is not presented for each monomer`;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < data.molecule.length; i++) {
|
|
31
|
+
const linkData = this.getLinkData(data.molecule[i], data.MonomerCaps[i], data.MonomerName[i]);
|
|
32
|
+
const entry = {
|
|
33
|
+
mol: data.molecule[i],
|
|
34
|
+
type: 'Peptide',
|
|
35
|
+
code: data.MonomerCode[i],
|
|
36
|
+
analogueCode: data.MonomerNaturalAnalogCode[i],
|
|
37
|
+
linkages: linkData,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const name = data.MonomerCode[i] !== '.' ? data.MonomerCode[i] : data.MonomerName[i];
|
|
41
|
+
this.library[name] = entry;
|
|
42
|
+
this.monomers.push(data.MonomerName[i]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** getting full monomer information from monomer library*/
|
|
47
|
+
public getMonomerEntry(name: string) {
|
|
48
|
+
if (!this.monomers.includes(name))
|
|
49
|
+
throw `Monomer library do not contain ${name} monomer`;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
return this.library[name];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** getting mol as string for monomer*/
|
|
56
|
+
public getMonomerMol(name: string) {
|
|
57
|
+
if (!this.monomers.includes(name))
|
|
58
|
+
throw `Monomer library do not contain ${name} monomer`;
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
const entry = this.library[name];
|
|
62
|
+
let monomerMol = entry.mol.replace(/M RGP .+\n/, '');
|
|
63
|
+
|
|
64
|
+
//order matters
|
|
65
|
+
const links = Object.keys(entry.linkages);
|
|
66
|
+
for (let i = 0; i < links.length; i++)
|
|
67
|
+
monomerMol = monomerMol.replace('R#', entry.linkages[links[i]].type + ' ');
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
return monomerMol;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** getting the list of the minomers available in library*/
|
|
74
|
+
get monomerNames() {
|
|
75
|
+
return this.monomers;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private getLinkData(mol: string, caps: string, name: string) {
|
|
79
|
+
const rawData = mol.match(/M RGP .+/);
|
|
80
|
+
if (rawData === null)
|
|
81
|
+
throw `Monomer library was not compiled: ${name} entry has no RGP`;
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
const types: { [code: string]: string } = {};
|
|
85
|
+
caps.split('\n')?.forEach((e) => {
|
|
86
|
+
types[e.match(/\d+/)![0]] = e.match(/(?<=\])\w+/)![0];
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const data = rawData![0].replace('M RGP ', '').split(/\s+/);
|
|
90
|
+
const res: { [link: string]: { atomNumber: number, type: string } } = {};
|
|
91
|
+
for (let i = 0; i < parseInt(data[0]); i++) {
|
|
92
|
+
const code = parseInt(data[2 * i + 2]);
|
|
93
|
+
let type = '';
|
|
94
|
+
switch (code) {
|
|
95
|
+
case 1:
|
|
96
|
+
type = 'N-terminal';
|
|
97
|
+
break;
|
|
98
|
+
case 2:
|
|
99
|
+
type = 'C-terminal';
|
|
100
|
+
break;
|
|
101
|
+
case 3:
|
|
102
|
+
type = 'branch';
|
|
103
|
+
break;
|
|
104
|
+
default:
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
res[type] = {atomNumber: parseInt(data[2 * i + 1]), type: types[code]};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return res;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//TODO: merge with Chem version
|
|
115
|
+
class SDFReader {
|
|
116
|
+
dataColls: { [_: string]: any };
|
|
117
|
+
|
|
118
|
+
constructor() {
|
|
119
|
+
this.dataColls = {'molecule': []};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get_colls(content: string) {
|
|
123
|
+
this.read(content);
|
|
124
|
+
return this.dataColls;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
read(content: string) {
|
|
128
|
+
content = content.replaceAll('\r', ''); //equalize old and new sdf standards
|
|
129
|
+
let startIndex = content.indexOf('$$$$', 0);
|
|
130
|
+
this.parse(content, 0, startIndex, (name: string, val: any) => { // TODO: type
|
|
131
|
+
this.dataColls[name] = [];
|
|
132
|
+
this.dataColls[name].push(val);
|
|
133
|
+
});
|
|
134
|
+
startIndex += 5;
|
|
135
|
+
while (startIndex > -1 && startIndex < content.length)
|
|
136
|
+
startIndex = this.readNext(content, startIndex);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
readNext(content: string, startIndex: number) {
|
|
140
|
+
const nextStartIndex = content.indexOf('$$$$', startIndex);
|
|
141
|
+
if (nextStartIndex === -1)
|
|
142
|
+
return -1;
|
|
143
|
+
else {
|
|
144
|
+
this.parse(content, startIndex, nextStartIndex,
|
|
145
|
+
(name: string, val: number) => this.dataColls[name].push(val));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (nextStartIndex > -1)
|
|
149
|
+
return nextStartIndex + 5;
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
return nextStartIndex;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
parse(content: string, start: number, end: number, handler: any) {
|
|
156
|
+
const molEnd = +content.indexOf('M END\n', start) + 7;
|
|
157
|
+
let localEnd = start;
|
|
158
|
+
this.dataColls['molecule'].push(content.substr(start, molEnd - start));
|
|
159
|
+
|
|
160
|
+
start = molEnd;
|
|
161
|
+
while (localEnd < end) {
|
|
162
|
+
start = content.indexOf('> <', localEnd);
|
|
163
|
+
if (start === -1)
|
|
164
|
+
return;
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
start += 3;
|
|
168
|
+
localEnd = content.indexOf('>\n', start);
|
|
169
|
+
if (localEnd === -1)
|
|
170
|
+
return;
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
const propertyName = content.substring(start, localEnd);
|
|
174
|
+
start = localEnd + 2;
|
|
175
|
+
|
|
176
|
+
localEnd = content.indexOf('\n', start);
|
|
177
|
+
if (localEnd === -1)
|
|
178
|
+
localEnd = end;
|
|
179
|
+
else if (content[localEnd + 1] != '\n')
|
|
180
|
+
localEnd = content.indexOf('\n', ++localEnd);
|
|
181
|
+
;
|
|
182
|
+
|
|
183
|
+
handler(propertyName, content.substring(start, localEnd));
|
|
184
|
+
localEnd += 2;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
package/src/package.ts
CHANGED
|
@@ -38,9 +38,9 @@ async function main(chosenFile: string) {
|
|
|
38
38
|
pi.close();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
//name: Peptides
|
|
41
|
+
//name: Peptides
|
|
42
42
|
//tags: app
|
|
43
|
-
export function Peptides() {
|
|
43
|
+
export async function Peptides() {
|
|
44
44
|
const wikiLink = ui.link('wiki', 'https://github.com/datagrok-ai/public/blob/master/help/domains/bio/peptides.md');
|
|
45
45
|
const textLink = ui.inlineText(['For more details, see our ', wikiLink, '.']);
|
|
46
46
|
|
|
@@ -73,8 +73,8 @@ export function Peptides() {
|
|
|
73
73
|
appDescription,
|
|
74
74
|
ui.info([textLink]),
|
|
75
75
|
ui.divH([
|
|
76
|
-
ui.button('
|
|
77
|
-
ui.button('
|
|
76
|
+
ui.button('Simple demo', () => main('aligned.csv'), ''),
|
|
77
|
+
ui.button('Complex demo', () => main('aligned_2.csv'), ''),
|
|
78
78
|
]),
|
|
79
79
|
]);
|
|
80
80
|
}
|
|
@@ -84,9 +84,9 @@ export function Peptides() {
|
|
|
84
84
|
//input: column col {semType: alignedSequence}
|
|
85
85
|
//output: widget result
|
|
86
86
|
export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
|
|
87
|
-
if (col.getTag('isAnalysisApplicable') === 'false')
|
|
87
|
+
if (col.getTag('isAnalysisApplicable') === 'false')
|
|
88
88
|
return new DG.Widget(ui.divText('Analysis is not applicable'));
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
view = (grok.shell.v as DG.TableView);
|
|
91
91
|
tableGrid = view.grid;
|
|
92
92
|
currentDf = col.dataFrame;
|
|
@@ -136,6 +136,15 @@ export async function peptideMolecule(peptide: string): Promise<DG.Widget> {
|
|
|
136
136
|
return await peptideMoleculeWidget(peptide);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
//name: Peptide Molecule
|
|
140
|
+
//tags: panel, widgets
|
|
141
|
+
//input: string aar {semType: aminoAcids}
|
|
142
|
+
//output: widget result
|
|
143
|
+
export async function peptideMolecule2(aar: string): Promise<DG.Widget> {
|
|
144
|
+
const peptide = alignedSequenceCol.get(currentDf.currentRowIdx);
|
|
145
|
+
return await peptideMolecule(peptide);
|
|
146
|
+
}
|
|
147
|
+
|
|
139
148
|
//name: StackedBarChartAA
|
|
140
149
|
//tags: viewer
|
|
141
150
|
//output: viewer result
|
|
@@ -171,6 +180,7 @@ export function logov() {
|
|
|
171
180
|
//input: string monomer {semType: aminoAcids}
|
|
172
181
|
//output: widget result
|
|
173
182
|
export function manualAlignment(monomer: string) {
|
|
183
|
+
//TODO: recalculate Molfile and Molecule panels on sequence update
|
|
174
184
|
return manualAlignmentWidget(alignedSequenceCol, currentDf);
|
|
175
185
|
}
|
|
176
186
|
|
|
@@ -192,6 +202,15 @@ export async function peptideMolfile(peptide: string): Promise<DG.Widget> {
|
|
|
192
202
|
return await grok.functions.call('Chem:molfile', {'smiles': smiles});
|
|
193
203
|
}
|
|
194
204
|
|
|
205
|
+
//name: Molfile
|
|
206
|
+
//tags: panel, widgets
|
|
207
|
+
//input: string aar { semType: aminoAcids }
|
|
208
|
+
//output: widget result
|
|
209
|
+
export async function peptideMolfile2(aar: string): Promise<DG.Widget> {
|
|
210
|
+
const peptide = alignedSequenceCol.get(currentDf.currentRowIdx);
|
|
211
|
+
return await peptideMolfile(peptide);
|
|
212
|
+
}
|
|
213
|
+
|
|
195
214
|
//name: Multiple sequence alignment
|
|
196
215
|
//tags: panel
|
|
197
216
|
//input: column col {semType: alignedSequence}
|
package/src/peptides.ts
CHANGED
|
@@ -59,10 +59,14 @@ export class Peptides {
|
|
|
59
59
|
// const layout1 = view.saveLayout();
|
|
60
60
|
// view.dockManager.close(substNode);
|
|
61
61
|
|
|
62
|
+
const helpUrl = '/help/domains/bio/peptides.md';
|
|
63
|
+
|
|
62
64
|
const sarViewer = view.addViewer('peptide-sar-viewer', options);
|
|
65
|
+
sarViewer.helpUrl = helpUrl;
|
|
63
66
|
const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
|
|
64
67
|
|
|
65
68
|
const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
|
|
69
|
+
sarViewerVertical.helpUrl = helpUrl;
|
|
66
70
|
const sarVNode = view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
|
|
67
71
|
|
|
68
72
|
const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
|
|
@@ -87,17 +91,15 @@ export class Peptides {
|
|
|
87
91
|
const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
|
|
88
92
|
const viewers = [];
|
|
89
93
|
for (const viewer of view.viewers) {
|
|
90
|
-
if (viewer.type !== DG.VIEWER.GRID)
|
|
94
|
+
if (viewer.type !== DG.VIEWER.GRID)
|
|
91
95
|
viewers.push(viewer);
|
|
92
|
-
}
|
|
93
96
|
}
|
|
94
97
|
viewers.forEach((v) => v.close());
|
|
95
98
|
|
|
96
99
|
const cols = (currentDf.columns as DG.ColumnList);
|
|
97
100
|
for (const colName of cols.names()) {
|
|
98
|
-
if (!originalDfColumns.includes(colName))
|
|
101
|
+
if (!originalDfColumns.includes(colName))
|
|
99
102
|
cols.remove(colName);
|
|
100
|
-
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
currentDf.selection.setAll(false);
|
|
@@ -132,9 +134,11 @@ export class Peptides {
|
|
|
132
134
|
nodeList.length = 0;
|
|
133
135
|
if (isSA) {
|
|
134
136
|
const sarViewer = view.addViewer('peptide-sar-viewer', options);
|
|
137
|
+
sarViewer.helpUrl = helpUrl;
|
|
135
138
|
const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
|
|
136
139
|
|
|
137
140
|
const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
|
|
141
|
+
sarViewerVertical.helpUrl = helpUrl;
|
|
138
142
|
const sarVNode = view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
|
|
139
143
|
|
|
140
144
|
const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
|
|
@@ -152,7 +156,8 @@ export class Peptides {
|
|
|
152
156
|
const substViewer = view.addViewer(
|
|
153
157
|
'substitution-analysis-viewer', {'activityColumnName': options['activityColumnName']},
|
|
154
158
|
);
|
|
155
|
-
|
|
159
|
+
substViewer.helpUrl = helpUrl;
|
|
160
|
+
nodeList.push(view.dockManager.dock(substViewer, DG.DOCK_TYPE.DOWN, null, 'Substitution Analysis'));
|
|
156
161
|
$(switchViewers).removeClass('fa-toggle-on');
|
|
157
162
|
$(switchViewers).addClass('fa-toggle-off');
|
|
158
163
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {after, before, category,
|
|
2
|
-
import {splitAlignedPeptides} from
|
|
3
|
-
import * as DG from
|
|
4
|
-
import * as grok from
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import {after, before, category, test} from '@datagrok-libraries/utils/src/test';
|
|
2
|
+
import {splitAlignedPeptides} from '../utils/split-aligned';
|
|
3
|
+
import * as DG from 'datagrok-api/dg';
|
|
4
|
+
import * as grok from 'datagrok-api/grok';
|
|
5
|
+
import {Peptides} from '../peptides';
|
|
6
|
+
import {describe} from '../describe';
|
|
7
|
+
import {analyzePeptidesWidget} from '../widgets/analyze-peptides';
|
|
8
|
+
import {manualAlignmentWidget} from '../widgets/manual-alignment';
|
|
9
|
+
import {peptideMoleculeWidget} from '../widgets/peptide-molecule';
|
|
10
|
+
import * as P from '../package';
|
|
11
|
+
|
|
12
|
+
// let _package = new DG.Package();
|
|
13
13
|
|
|
14
14
|
category('peptides', async () => {
|
|
15
15
|
let peptidesDf: DG.DataFrame;
|
|
@@ -19,7 +19,7 @@ category('peptides', async () => {
|
|
|
19
19
|
let pepView: DG.TableView;
|
|
20
20
|
|
|
21
21
|
before(async () => {
|
|
22
|
-
// peptidesDf = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned.csv'));
|
|
22
|
+
// peptidesDf = DG.DataFrame.fromCsv(await P._package.files.readAsText('aligned.csv'));
|
|
23
23
|
const csv = `ID,AlignedSequence,IC50
|
|
24
24
|
1,NH2--A-Q-T-T-Y-K-N-Y-R-R-N-L-L--COOH,4.6411368455908086e-4
|
|
25
25
|
2,NH2-M-A-N-T-T-Y-K-N-Y-R-N-N-L-L--COOH,0.003327324930165897
|
|
@@ -45,9 +45,9 @@ category('peptides', async () => {
|
|
|
45
45
|
'activityColumnName': 'IC50',
|
|
46
46
|
'scaling': '-lg',
|
|
47
47
|
};
|
|
48
|
-
peptidesGrid = peptidesDf.plot.grid();
|
|
49
48
|
asCol = peptidesDf.getCol('AlignedSequence');
|
|
50
49
|
pepView = grok.shell.addTableView(peptidesDf);
|
|
50
|
+
peptidesGrid = pepView.grid;
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
test('utils.split-sequence', async () => {
|
|
@@ -56,7 +56,7 @@ category('peptides', async () => {
|
|
|
56
56
|
|
|
57
57
|
test('describe', async () => {
|
|
58
58
|
await describe(
|
|
59
|
-
peptidesDf, options['activityColumnName'], options['scaling'],
|
|
59
|
+
peptidesDf, options['activityColumnName'], options['scaling'], peptidesGrid, true,
|
|
60
60
|
DG.BitSet.create(peptidesDf.rowCount, (i) => i % 2 === 0), true);
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -65,6 +65,10 @@ category('peptides', async () => {
|
|
|
65
65
|
peptides.init(peptidesGrid, pepView, peptidesDf, options, asCol);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
test('panel.peptides', async () => {
|
|
69
|
+
await P.peptidesPanel(asCol);
|
|
70
|
+
});
|
|
71
|
+
|
|
68
72
|
test('widgets.analyze-peptides', async () => {
|
|
69
73
|
await analyzePeptidesWidget(asCol, pepView, peptidesGrid, peptidesDf);
|
|
70
74
|
});
|
|
@@ -77,8 +81,40 @@ category('peptides', async () => {
|
|
|
77
81
|
await peptideMoleculeWidget('NH2--A-N-T-T-Y-K-N-Y-R-S-N-L-L--COOH');
|
|
78
82
|
});
|
|
79
83
|
|
|
84
|
+
test('widgets.molfile', async () => {
|
|
85
|
+
await P.peptideMolfile2('');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('renderers.aligned-sequence-cell', async () => {
|
|
89
|
+
P.alignedSequenceCellRenderer();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('renderers.amino-acids-cell', async () => {
|
|
93
|
+
P.aminoAcidsCellRenderer();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('viewers.logo-viewer', async () => {
|
|
97
|
+
P.logov();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('viewers.sar-viewer', async () => {
|
|
101
|
+
P.sar();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('viewers.sar-vertical-viewer', async () => {
|
|
105
|
+
P.sarVertical();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('viewers.stacked-barchart-viewer', async () => {
|
|
109
|
+
P.stackedBarChart();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('viewers.subst-viewer', async () => {
|
|
113
|
+
P.subst();
|
|
114
|
+
});
|
|
115
|
+
|
|
80
116
|
after(async () => {
|
|
81
117
|
pepView.close();
|
|
82
118
|
grok.shell.closeTable(peptidesDf);
|
|
83
|
-
})
|
|
119
|
+
});
|
|
84
120
|
});
|
package/src/tests/utils.ts
CHANGED
|
@@ -77,9 +77,8 @@ export async function _testPeptideSimilaritySpaceViewer(
|
|
|
77
77
|
const axesNames = ['~X', '~Y', '~MW'];
|
|
78
78
|
const axes = axesNames.map((v) => df?.getCol(v).getRawData() as Float32Array);
|
|
79
79
|
|
|
80
|
-
for (const ax of axes)
|
|
80
|
+
for (const ax of axes)
|
|
81
81
|
expect(ax.every((v) => v !== null && v !== NaN), true);
|
|
82
|
-
}
|
|
83
82
|
} catch (error) {
|
|
84
83
|
noException = false;
|
|
85
84
|
}
|