@datagrok/peptides 0.6.0 → 0.6.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/detectors.js +1 -1
- package/package.json +3 -1
- package/src/describe.ts +24 -21
- package/src/package.ts +7 -11
- package/src/peptides.ts +44 -2
- package/src/styles.css +37 -0
- package/src/utils/chem-palette.ts +2 -2
- package/src/viewers/sar-viewer.ts +14 -14
- package/src/viewers/subst-viewer.ts +78 -46
- package/src/widgets/analyze-peptides.ts +2 -2
- package/src/widgets/manual-alignment.ts +5 -5
- package/webpack.config.js +4 -0
package/detectors.js
CHANGED
|
@@ -3,7 +3,7 @@ class PeptidesPackageDetectors extends DG.Package {
|
|
|
3
3
|
//input: column col
|
|
4
4
|
//output: string semType
|
|
5
5
|
detectAligned(col) {
|
|
6
|
-
const regexp = new RegExp(/^([^-^\n]*-){
|
|
6
|
+
const regexp = new RegExp(/^([^-^\n]*-){7,49}(\w|\(|\))+$/);
|
|
7
7
|
return DG.Detector.sampleCategories(col, (s) => regexp.test(s.trim())) ? 'alignedSequence' : null;
|
|
8
8
|
}
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@keckelt/tsne": "^1.0.2",
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"typescript": "^4.4.4",
|
|
23
23
|
"ts-loader": "^9.2.5",
|
|
24
|
+
"css-loader": "^5.2.4",
|
|
25
|
+
"style-loader": "^2.0.0",
|
|
24
26
|
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
|
25
27
|
"@typescript-eslint/parser": "^4.29.1",
|
|
26
28
|
"eslint": "^7.32.0",
|
package/src/describe.ts
CHANGED
|
@@ -178,7 +178,7 @@ export async function describe(
|
|
|
178
178
|
|
|
179
179
|
//calculate p-values based on t-test
|
|
180
180
|
let position: string;
|
|
181
|
-
let
|
|
181
|
+
let aar: string;
|
|
182
182
|
let currentActivity: number[];
|
|
183
183
|
let otherActivity: number[];
|
|
184
184
|
let testResult;
|
|
@@ -190,17 +190,17 @@ export async function describe(
|
|
|
190
190
|
const pValCol: DG.Column = matrixDf.columns.addNewFloat('pValue');
|
|
191
191
|
for (let i = 0; i < matrixDf.rowCount; i++) {
|
|
192
192
|
position = matrixDf.get(positionColName, i);
|
|
193
|
-
|
|
193
|
+
aar = matrixDf.get(aminoAcidResidue, i);
|
|
194
194
|
|
|
195
195
|
//@ts-ignore
|
|
196
|
-
splitSeqDf.rows.select((row) => groupMapping[row[position]] ===
|
|
196
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] === aar);
|
|
197
197
|
currentActivity = splitSeqDf
|
|
198
198
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
199
199
|
.getCol(activityColumnScaled)
|
|
200
200
|
.toList();
|
|
201
201
|
|
|
202
202
|
//@ts-ignore
|
|
203
|
-
splitSeqDf.rows.select((row) => groupMapping[row[position]] !==
|
|
203
|
+
splitSeqDf.rows.select((row) => groupMapping[row[position]] !== aar);
|
|
204
204
|
otherActivity = splitSeqDf
|
|
205
205
|
.clone(splitSeqDf.selection, [activityColumnScaled])
|
|
206
206
|
.getCol(activityColumnScaled)
|
|
@@ -271,23 +271,23 @@ export async function describe(
|
|
|
271
271
|
renderColNames.push('Mean difference');
|
|
272
272
|
|
|
273
273
|
// !!! DRAWING PHASE !!!
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
const sarGrid = matrixDf.plot.grid();
|
|
275
|
+
sarGrid.sort([aminoAcidResidue]);
|
|
276
|
+
sarGrid.columns.setOrder([aminoAcidResidue].concat(positionColumns));
|
|
277
277
|
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
278
|
+
const sarVGrid = sequenceDf.plot.grid();
|
|
279
|
+
sarVGrid.sort([positionColName]);
|
|
280
|
+
sarVGrid.col('pValue')!.format = 'four digits after comma';
|
|
281
|
+
sarVGrid.col('pValue')!.name = 'P-Value';
|
|
282
282
|
|
|
283
283
|
if (!grouping) {
|
|
284
284
|
let tempCol = matrixDf.columns.byName(aminoAcidResidue);
|
|
285
285
|
if (tempCol) {
|
|
286
|
-
setAARRenderer(tempCol,
|
|
286
|
+
setAARRenderer(tempCol, sarGrid);
|
|
287
287
|
}
|
|
288
288
|
tempCol = sequenceDf.columns.byName(aminoAcidResidue);
|
|
289
289
|
if (tempCol) {
|
|
290
|
-
setAARRenderer(tempCol,
|
|
290
|
+
setAARRenderer(tempCol, sarGrid);
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
|
|
@@ -358,8 +358,8 @@ export async function describe(
|
|
|
358
358
|
}
|
|
359
359
|
args.g.restore();
|
|
360
360
|
};
|
|
361
|
-
|
|
362
|
-
|
|
361
|
+
sarGrid.onCellRender.subscribe(cellRendererFunc);
|
|
362
|
+
sarVGrid.onCellRender.subscribe(cellRendererFunc);
|
|
363
363
|
|
|
364
364
|
// show all the statistics in a tooltip over cell
|
|
365
365
|
const onCellTooltipFunc = function(cell: DG.GridCell, x: number, y: number) {
|
|
@@ -412,8 +412,8 @@ export async function describe(
|
|
|
412
412
|
}
|
|
413
413
|
return true;
|
|
414
414
|
};
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
sarGrid.onCellTooltip(onCellTooltipFunc);
|
|
416
|
+
sarVGrid.onCellTooltip(onCellTooltipFunc);
|
|
417
417
|
|
|
418
418
|
sourceGrid.onCellPrepare((cell: DG.GridCell) => {
|
|
419
419
|
const currentRowIndex = cell.tableRowIndex;
|
|
@@ -423,13 +423,16 @@ export async function describe(
|
|
|
423
423
|
});
|
|
424
424
|
|
|
425
425
|
for (const col of matrixDf.columns.names()) {
|
|
426
|
-
|
|
426
|
+
sarGrid.col(col)!.width = sarGrid.props.rowHeight;
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
if (grouping) {
|
|
430
|
-
|
|
431
|
-
|
|
430
|
+
sarGrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
431
|
+
sarVGrid.col(aminoAcidResidue)!.name = 'Groups';
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
|
|
434
|
+
sarGrid.props.allowEdit = false;
|
|
435
|
+
sarVGrid.props.allowEdit = false;
|
|
436
|
+
|
|
437
|
+
return [sarGrid, sarVGrid, statsDf, groupMapping];
|
|
435
438
|
}
|
package/src/package.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {manualAlignmentWidget} from './widgets/manual-alignment';
|
|
|
16
16
|
import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
|
|
17
17
|
import {peptideMoleculeWidget} from './widgets/peptide-molecule';
|
|
18
18
|
import {SpiralPlot} from './viewers/spiral-plot';
|
|
19
|
-
import {
|
|
19
|
+
import {SubstViewer} from './viewers/subst-viewer';
|
|
20
20
|
|
|
21
21
|
export const _package = new DG.Package();
|
|
22
22
|
let tableGrid: DG.Grid;
|
|
@@ -64,25 +64,18 @@ export function Peptides() {
|
|
|
64
64
|
'Use and analyse peptide sequence data to support your research:',
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
-
const annotationViewerDiv = ui.div();
|
|
68
|
-
|
|
69
67
|
const windows = grok.shell.windows;
|
|
70
68
|
windows.showToolbox = false;
|
|
71
69
|
windows.showHelp = false;
|
|
72
70
|
windows.showProperties = false;
|
|
73
71
|
|
|
74
|
-
const mainDiv = ui.div();
|
|
75
72
|
grok.shell.newView('Peptides', [
|
|
76
73
|
appDescription,
|
|
77
74
|
ui.info([textLink]),
|
|
78
|
-
ui.
|
|
79
|
-
ui.
|
|
80
|
-
|
|
81
|
-
ui.button('Open complex case demo', () => main('aligned_2.csv'), ''),
|
|
82
|
-
]),
|
|
83
|
-
ui.block75([annotationViewerDiv]),
|
|
75
|
+
ui.divH([
|
|
76
|
+
ui.button('Open peptide sequences demonstration set', () => main('aligned.csv'), ''),
|
|
77
|
+
ui.button('Open complex case demo', () => main('aligned_2.csv'), ''),
|
|
84
78
|
]),
|
|
85
|
-
mainDiv,
|
|
86
79
|
]);
|
|
87
80
|
}
|
|
88
81
|
|
|
@@ -91,6 +84,9 @@ export function Peptides() {
|
|
|
91
84
|
//input: column col {semType: alignedSequence}
|
|
92
85
|
//output: widget result
|
|
93
86
|
export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
|
|
87
|
+
if (col.getTag('isAnalysisApplicable') === 'false') {
|
|
88
|
+
return new DG.Widget(ui.divText('Analysis is not applicable'));
|
|
89
|
+
}
|
|
94
90
|
view = (grok.shell.v as DG.TableView);
|
|
95
91
|
tableGrid = view.grid;
|
|
96
92
|
currentDf = col.dataFrame;
|
package/src/peptides.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
import {createPeptideSimilaritySpaceViewer} from './utils/peptide-similarity-space';
|
|
4
4
|
import {addViewerToHeader} from './viewers/stacked-barchart-viewer';
|
|
5
|
+
// import $ from 'cash-dom';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Peptides controller class.
|
|
@@ -41,9 +42,10 @@ export class Peptides {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
|
|
45
|
+
const originalDfName = currentDf.name;
|
|
44
46
|
|
|
45
47
|
const substViewer = view.addViewer(
|
|
46
|
-
'substitution-analysis-viewer', {'activityColumnName': options['
|
|
48
|
+
'substitution-analysis-viewer', {'activityColumnName': options['activityColumnName']},
|
|
47
49
|
);
|
|
48
50
|
view.dockManager.dock(substViewer, DG.DOCK_TYPE.RIGHT, null, 'Substitution Analysis');
|
|
49
51
|
|
|
@@ -62,10 +64,13 @@ export class Peptides {
|
|
|
62
64
|
view,
|
|
63
65
|
`${activityColumnChoice}Scaled`,
|
|
64
66
|
);
|
|
65
|
-
view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
|
|
67
|
+
const psNode = view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
|
|
68
|
+
// const sarDockNodes = [sarNode, sarVNode, psNode];
|
|
69
|
+
// const sarViewers = [sarViewer, sarViewerVertical, peptideSpaceViewer];
|
|
66
70
|
|
|
67
71
|
const StackedBarchartProm = currentDf.plot.fromType('StackedBarChartAA');
|
|
68
72
|
addViewerToHeader(tableGrid, StackedBarchartProm);
|
|
73
|
+
tableGrid.props.allowEdit = false;
|
|
69
74
|
|
|
70
75
|
const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
|
|
71
76
|
const viewers = [];
|
|
@@ -88,10 +93,47 @@ export class Peptides {
|
|
|
88
93
|
|
|
89
94
|
tableGrid.setOptions({'colHeaderHeight': 20});
|
|
90
95
|
tableGrid.columns.setVisible(originalDfColumns);
|
|
96
|
+
tableGrid.props.allowEdit = true;
|
|
97
|
+
currentDf.name = originalDfName;
|
|
91
98
|
|
|
92
99
|
view.setRibbonPanels(ribbonPanels);
|
|
93
100
|
}, 'Close viewers and restore dataframe');
|
|
94
101
|
|
|
102
|
+
// let substViewer: DG.Viewer | null = null;
|
|
103
|
+
// let substNode: DG.DockNode | null = null;
|
|
104
|
+
// let isSA = false;
|
|
105
|
+
// let viewLayout1: DG.ViewLayout | null = null;
|
|
106
|
+
// let viewLayout2: DG.ViewLayout | null = null;
|
|
107
|
+
// const switchViewers = ui.iconFA('toggle-on', () => {
|
|
108
|
+
// if (isSA) {
|
|
109
|
+
// viewLayout2 = view.saveLayout();
|
|
110
|
+
// // view.dockManager.close(substNode!);
|
|
111
|
+
// substViewer?.close();
|
|
112
|
+
|
|
113
|
+
// view.loadLayout(viewLayout1!);
|
|
114
|
+
|
|
115
|
+
// $(switchViewers).removeClass('fa-toggle-off');
|
|
116
|
+
// $(switchViewers).addClass('fa-toggle-on');
|
|
117
|
+
// } else {
|
|
118
|
+
// viewLayout1 = view.saveLayout();
|
|
119
|
+
// // sarDockNodes.forEach((node) => view.dockManager.close(node));
|
|
120
|
+
// sarViewers.forEach((v) => v.close());
|
|
121
|
+
|
|
122
|
+
// if (viewLayout2 === null) {
|
|
123
|
+
// substViewer = view.addViewer(
|
|
124
|
+
// 'substitution-analysis-viewer', {'activityColumnName': options['activityColumnName']},
|
|
125
|
+
// );
|
|
126
|
+
// substNode = view.dockManager.dock(substViewer, DG.DOCK_TYPE.DOWN, null, 'Substitution Analysis');
|
|
127
|
+
// } else {
|
|
128
|
+
// view.loadLayout(viewLayout2);
|
|
129
|
+
// }
|
|
130
|
+
|
|
131
|
+
// $(switchViewers).removeClass('fa-toggle-on');
|
|
132
|
+
// $(switchViewers).addClass('fa-toggle-off');
|
|
133
|
+
// }
|
|
134
|
+
// isSA = !isSA;
|
|
135
|
+
// });
|
|
136
|
+
|
|
95
137
|
const ribbonPanels = view.getRibbonPanels();
|
|
96
138
|
view.setRibbonPanels([[hideIcon]]);
|
|
97
139
|
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.pep-textarea-box {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.pep-textarea-box:hover .pep-snippet-editor-icon {
|
|
6
|
+
visibility: visible;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.pep-snippet-editor-icon {
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 5px;
|
|
12
|
+
visibility: hidden;
|
|
13
|
+
margin: 5px;
|
|
14
|
+
z-index: 1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.pep-reset-icon {
|
|
18
|
+
right: 10px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.pep-snippet-editor-icon i {
|
|
22
|
+
font-size: 13px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.pep-snippet-editor-icon:hover {
|
|
26
|
+
background-color: var(--steel-1);
|
|
27
|
+
border-radius: 2px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.pep-snippet-inline-icon i {
|
|
31
|
+
font-size: 13px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.pep-textinput {
|
|
35
|
+
height: 50px;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
}
|
|
@@ -56,7 +56,7 @@ export class ChemPalette {
|
|
|
56
56
|
/**
|
|
57
57
|
* Get color for the provided amino acid residue.
|
|
58
58
|
* @param {string} c Amino acid residue string.
|
|
59
|
-
* @
|
|
59
|
+
* @return {string} Color.
|
|
60
60
|
*/
|
|
61
61
|
getColor(c: string): string {
|
|
62
62
|
const [color] = this.getColorPivot(c);
|
|
@@ -66,7 +66,7 @@ export class ChemPalette {
|
|
|
66
66
|
/**
|
|
67
67
|
* Get color for the provided amino acid residue pivot
|
|
68
68
|
* @param {string} [c=''] Amino acid residue string.
|
|
69
|
-
* @
|
|
69
|
+
* @return {[string, string, number]}
|
|
70
70
|
*/
|
|
71
71
|
getColorAAPivot(c: string = ''): [string, string, number] {
|
|
72
72
|
if (c.length == 1 || c[1] == '(') {
|
|
@@ -16,8 +16,8 @@ import {model} from './model';
|
|
|
16
16
|
export class SARViewer extends DG.JsViewer {
|
|
17
17
|
protected viewerGrid: DG.Grid | null;
|
|
18
18
|
protected sourceGrid: DG.Grid | null;
|
|
19
|
-
protected
|
|
20
|
-
protected
|
|
19
|
+
protected activityColumnName: string;
|
|
20
|
+
protected scaling: string;
|
|
21
21
|
protected bidirectionalAnalysis: boolean;
|
|
22
22
|
protected filterMode: boolean;
|
|
23
23
|
protected statsDf: DG.DataFrame | null;
|
|
@@ -51,9 +51,9 @@ export class SARViewer extends DG.JsViewer {
|
|
|
51
51
|
this.viewGridInitialized = false;
|
|
52
52
|
this.currentBitset = null;
|
|
53
53
|
|
|
54
|
-
//TODO: find a way to restrict
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
54
|
+
//TODO: find a way to restrict activityColumnName to accept only numerical columns (double even better)
|
|
55
|
+
this.activityColumnName = this.string('activityColumnName');
|
|
56
|
+
this.scaling = this.string('scaling', 'none', {choices: ['none', 'lg', '-lg']});
|
|
57
57
|
this.filterMode = this.bool('filterMode', false);
|
|
58
58
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
59
59
|
this.grouping = this.bool('grouping', false);
|
|
@@ -115,14 +115,14 @@ export class SARViewer extends DG.JsViewer {
|
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
if (property.name === '
|
|
118
|
+
if (property.name === 'scaling' && typeof this.dataFrame !== 'undefined') {
|
|
119
119
|
const minActivity = DG.Stats.fromColumn(
|
|
120
|
-
this.dataFrame!.col(this.
|
|
120
|
+
this.dataFrame!.col(this.activityColumnName)!,
|
|
121
121
|
this._initialBitset,
|
|
122
122
|
).min;
|
|
123
|
-
if (minActivity && minActivity <= 0 && this.
|
|
124
|
-
grok.shell.warning(`Could not apply ${this.
|
|
125
|
-
`activity column ${this.
|
|
123
|
+
if (minActivity && minActivity <= 0 && this.scaling !== 'none') {
|
|
124
|
+
grok.shell.warning(`Could not apply ${this.scaling}: ` +
|
|
125
|
+
`activity column ${this.activityColumnName} contains zero or negative values, falling back to 'none'.`);
|
|
126
126
|
property.set(this, 'none');
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
@@ -230,7 +230,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
230
230
|
const hist = originalDf.clone(this._initialBitset).plot.histogram({
|
|
231
231
|
// const hist = originalDf.plot.histogram({
|
|
232
232
|
filteringEnabled: false,
|
|
233
|
-
valueColumnName: `${this.
|
|
233
|
+
valueColumnName: `${this.activityColumnName}Scaled`,
|
|
234
234
|
splitColumnName: '~splitCol',
|
|
235
235
|
legendVisibility: 'Never',
|
|
236
236
|
showXAxis: true,
|
|
@@ -317,11 +317,11 @@ export class SARViewer extends DG.JsViewer {
|
|
|
317
317
|
}
|
|
318
318
|
//TODO: optimize. Don't calculate everything again if only view changes
|
|
319
319
|
if (computeData) {
|
|
320
|
-
if (typeof this.dataFrame !== 'undefined' && this.
|
|
320
|
+
if (typeof this.dataFrame !== 'undefined' && this.activityColumnName && this.sourceGrid) {
|
|
321
321
|
await model?.updateData(
|
|
322
322
|
this.dataFrame!,
|
|
323
|
-
this.
|
|
324
|
-
this.
|
|
323
|
+
this.activityColumnName,
|
|
324
|
+
this.scaling,
|
|
325
325
|
this.sourceGrid,
|
|
326
326
|
this.bidirectionalAnalysis,
|
|
327
327
|
this._initialBitset,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import * as grok from 'datagrok-api/grok';
|
|
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
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
// import {aarGroups} from '../describe';
|
|
8
|
+
import {setAARRenderer} from '../utils/cell-renderer';
|
|
9
9
|
|
|
10
10
|
export class SubstViewer extends DG.JsViewer {
|
|
11
11
|
viewerGrid: DG.Grid | null;
|
|
@@ -32,28 +32,27 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
32
32
|
|
|
33
33
|
calcSubstitutions() {
|
|
34
34
|
const aarColName = 'AAR';
|
|
35
|
-
|
|
36
|
-
let df: DG.DataFrame = this.dataFrame!;
|
|
35
|
+
const df: DG.DataFrame = this.dataFrame!;
|
|
37
36
|
const col: DG.Column = df.columns.bySemType('alignedSequence');
|
|
38
37
|
// let values: number[] = df.columns.byName('IC50').toList();
|
|
39
|
-
const values = df.getCol(this.activityColumnName).toList().map(x => -Math.log10(x));
|
|
38
|
+
const values = df.getCol(this.activityColumnName).toList().map((x) => -Math.log10(x));
|
|
40
39
|
// values = values;
|
|
41
|
-
splitedMatrix = this.split(col);
|
|
40
|
+
const splitedMatrix = this.split(col);
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const tableValues: { [aar: string]: number[] } = {};
|
|
43
|
+
const tableTooltips: { [aar: string]: {[index: string]: string}[][] } = {};
|
|
44
|
+
const tableCases: { [aar: string]: number[][][] } = {};
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
const nRows = splitedMatrix.length;
|
|
47
|
+
const nCols = splitedMatrix[0].length;
|
|
49
48
|
const nColsArray = Array(nCols);
|
|
50
49
|
|
|
51
50
|
for (let i = 0; i < nRows - 1; i++) {
|
|
52
51
|
for (let j = i + 1; j < nRows; j++) {
|
|
53
52
|
let substCounter = 0;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
const subst1: { [pos: number]: [string, {[index: string]: string}] } = {};
|
|
54
|
+
const subst2: { [pos: number]: [string, {[index: string]: string}] } = {};
|
|
55
|
+
const delta = values[i] - values[j];
|
|
57
56
|
|
|
58
57
|
for (let k = 0; k < nCols; k++) {
|
|
59
58
|
const smik = splitedMatrix[i][k];
|
|
@@ -62,53 +61,76 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
62
61
|
const vi = values[i].toFixed(2);
|
|
63
62
|
const vj = values[j].toFixed(2);
|
|
64
63
|
substCounter++;
|
|
65
|
-
subst1[k] = [
|
|
66
|
-
|
|
64
|
+
subst1[k] = [
|
|
65
|
+
smik,
|
|
66
|
+
{key: `${smik === '-' ? 'Empty' : smik} → ${smjk === '-' ? 'Empty' : smjk}`, value: `${vi} → ${vj}`},
|
|
67
|
+
];
|
|
68
|
+
subst2[k] = [
|
|
69
|
+
smjk,
|
|
70
|
+
{key: `${smjk === '-' ? 'Empty' : smjk} → ${smik === '-' ? 'Empty' : smik}`, value: `${vj} → ${vi}`},
|
|
71
|
+
];
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
if (substCounter <= this.maxSubstitutions && substCounter > 0) {
|
|
71
|
-
|
|
72
76
|
Object.keys(subst1).forEach((pos) => {
|
|
73
77
|
const posInt = parseInt(pos);
|
|
74
|
-
|
|
78
|
+
const aar = subst1[posInt][0];
|
|
75
79
|
if (!Object.keys(tableValues).includes(aar)) {
|
|
76
|
-
tableValues[aar] = Array.apply(null, nColsArray).map(function
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
tableValues[aar] = Array.apply(null, nColsArray).map(function() {
|
|
81
|
+
return DG.INT_NULL;
|
|
82
|
+
});
|
|
83
|
+
tableTooltips[aar] = Array.apply(null, nColsArray).map(function() {
|
|
84
|
+
return [];
|
|
85
|
+
});
|
|
86
|
+
tableCases[aar] = Array.apply(null, nColsArray).map(function() {
|
|
87
|
+
return [];
|
|
88
|
+
});
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
tableValues[aar][posInt] = tableValues[aar][posInt] === DG.INT_NULL ? 1 : tableValues[aar][posInt] + 1;
|
|
82
|
-
tableTooltips[aar][posInt] = tableTooltips[aar][posInt]
|
|
83
|
-
|
|
92
|
+
tableTooltips[aar][posInt] = !tableTooltips[aar][posInt].length ?
|
|
93
|
+
[{key: 'Substitution', value: 'Values'}] : tableTooltips[aar][posInt];
|
|
94
|
+
tableTooltips[aar][posInt].push(subst1[posInt][1]);
|
|
84
95
|
tableCases[aar][posInt].push([i, j, delta]);
|
|
85
96
|
});
|
|
86
97
|
Object.keys(subst2).forEach((pos) => {
|
|
87
98
|
const posInt = parseInt(pos);
|
|
88
|
-
|
|
99
|
+
const aar = subst2[posInt][0];
|
|
89
100
|
if (!Object.keys(tableValues).includes(aar)) {
|
|
90
|
-
tableValues[aar] = Array.apply(null, nColsArray).map(function
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
tableValues[aar] = Array.apply(null, nColsArray).map(function() {
|
|
102
|
+
return DG.INT_NULL;
|
|
103
|
+
});
|
|
104
|
+
tableTooltips[aar] = Array.apply(null, nColsArray).map(function() {
|
|
105
|
+
return [];
|
|
106
|
+
});
|
|
107
|
+
tableCases[aar] = Array.apply(null, nColsArray).map(function() {
|
|
108
|
+
return [];
|
|
109
|
+
});
|
|
93
110
|
}
|
|
94
111
|
|
|
95
112
|
tableValues[aar][posInt] = tableValues[aar][posInt] === DG.INT_NULL ? 1 : tableValues[aar][posInt] + 1;
|
|
96
113
|
// tableValues[aar][posInt]++;
|
|
97
|
-
tableTooltips[aar][posInt] = tableTooltips[aar][posInt]
|
|
98
|
-
|
|
114
|
+
tableTooltips[aar][posInt] = !tableTooltips[aar][posInt].length ?
|
|
115
|
+
[{key: 'Substitution', value: 'Values'}] : tableTooltips[aar][posInt];
|
|
116
|
+
tableTooltips[aar][posInt].push(subst2[posInt][1]);
|
|
99
117
|
tableCases[aar][posInt].push([j, i, -delta]);
|
|
100
118
|
});
|
|
101
119
|
}
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
|
|
105
|
-
const
|
|
106
|
-
const
|
|
123
|
+
const tableValuesKeys = Object.keys(tableValues);
|
|
124
|
+
const dfLength = tableValuesKeys.length;
|
|
125
|
+
const cols = [...nColsArray.keys()].map((v) => DG.Column.int(v.toString(), dfLength));
|
|
126
|
+
const aarCol = DG.Column.string(aarColName, dfLength);
|
|
107
127
|
cols.splice(0, 1, aarCol);
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
const table = DG.DataFrame.fromColumns(cols);
|
|
129
|
+
|
|
130
|
+
for (let i = 0; i < dfLength; i++) {
|
|
131
|
+
const aar = tableValuesKeys[i];
|
|
110
132
|
tableValues[aar].splice(0, 1);
|
|
111
|
-
table.rows.
|
|
133
|
+
table.rows.setValues(i, [aar, ...tableValues[aar]]);
|
|
112
134
|
}
|
|
113
135
|
|
|
114
136
|
// let groupMapping: { [key: string]: string } = {};
|
|
@@ -127,12 +149,15 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
127
149
|
if (colName !== aarColName) {
|
|
128
150
|
const aar = this.viewerGrid!.table.get(aarColName, gCell.tableRowIndex);
|
|
129
151
|
const pos = parseInt(colName);
|
|
130
|
-
const tooltipText = tableTooltips[aar][pos]
|
|
131
|
-
|
|
152
|
+
const tooltipText = tableTooltips[aar][pos].length ?
|
|
153
|
+
DG.HtmlTable.create(
|
|
154
|
+
tableTooltips[aar][pos], (item: {[index: string]: string}, idx: number) => [item.key, item.value],
|
|
155
|
+
).root : ui.divText('No substitutions');
|
|
156
|
+
ui.tooltip.show(tooltipText, x, y);
|
|
132
157
|
}
|
|
133
158
|
}
|
|
134
159
|
return true;
|
|
135
|
-
}
|
|
160
|
+
},
|
|
136
161
|
);
|
|
137
162
|
|
|
138
163
|
for (const col of table.columns.names()) {
|
|
@@ -146,28 +171,35 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
146
171
|
}
|
|
147
172
|
});
|
|
148
173
|
|
|
174
|
+
this.viewerGrid.props.allowEdit = false;
|
|
175
|
+
|
|
149
176
|
table.onCurrentCellChanged.subscribe((_) => {
|
|
150
177
|
if (table.currentCol !== null && table.currentCol.name !== aarColName && table.currentCell.value !== null) {
|
|
151
178
|
const aar = table.get(aarColName, table.currentRowIdx);
|
|
152
179
|
const pos = parseInt(table.currentCol.name);
|
|
153
180
|
const currentCase = tableCases[aar][pos];
|
|
154
|
-
const
|
|
155
|
-
const
|
|
181
|
+
const tempDfLength = currentCase.length;
|
|
182
|
+
const initCol = DG.Column.string('Initial', tempDfLength);
|
|
183
|
+
const subsCol = DG.Column.string('Substituted', tempDfLength);
|
|
156
184
|
|
|
157
185
|
const tempDf = DG.DataFrame.fromColumns([
|
|
158
186
|
initCol,
|
|
159
187
|
subsCol,
|
|
160
|
-
DG.Column.float('Difference'),
|
|
188
|
+
DG.Column.float('Difference', tempDfLength),
|
|
161
189
|
]);
|
|
162
190
|
|
|
163
|
-
for (
|
|
164
|
-
|
|
191
|
+
for (let i = 0; i < tempDfLength; i++) {
|
|
192
|
+
const row = currentCase[i];
|
|
193
|
+
tempDf.rows.setValues(i, [col.get(row[0]), col.get(row[1]), row[2]]);
|
|
165
194
|
}
|
|
166
195
|
|
|
167
196
|
initCol.semType = 'alignedSequence';
|
|
197
|
+
initCol.setTag('isAnalysisApplicable', 'false');
|
|
168
198
|
subsCol.semType = 'alignedSequence';
|
|
199
|
+
subsCol.setTag('isAnalysisApplicable', 'false');
|
|
169
200
|
|
|
170
201
|
this.casesGrid = tempDf.plot.grid();
|
|
202
|
+
this.casesGrid.props.allowEdit = false;
|
|
171
203
|
} else {
|
|
172
204
|
this.casesGrid = null;
|
|
173
205
|
}
|
|
@@ -180,7 +212,7 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
180
212
|
render() {
|
|
181
213
|
$(this.root).empty();
|
|
182
214
|
this.root.appendChild(this.casesGrid === null ?
|
|
183
|
-
this.viewerGrid!.root : ui.splitH([this.viewerGrid!.root, this.casesGrid.root])
|
|
215
|
+
this.viewerGrid!.root : ui.splitH([this.viewerGrid!.root, this.casesGrid.root]),
|
|
184
216
|
);
|
|
185
217
|
}
|
|
186
218
|
|
|
@@ -207,7 +239,7 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
207
239
|
// and marking invalid sequences
|
|
208
240
|
let nTerminal: string;
|
|
209
241
|
const invalidIndexes: number[] = [];
|
|
210
|
-
let splitColumns: string[][] = Array.from({
|
|
242
|
+
let splitColumns: string[][] = Array.from({length: modeMonomerCount}, (_) => []);
|
|
211
243
|
modeMonomerCount--; // minus N-terminal
|
|
212
244
|
for (let i = 0; i < colLength; i++) {
|
|
213
245
|
currentSplitPeptide = splitPeptidesArray[i];
|
|
@@ -224,7 +256,7 @@ export class SubstViewer extends DG.JsViewer {
|
|
|
224
256
|
modeMonomerCount--; // minus C-terminal
|
|
225
257
|
|
|
226
258
|
//create column names list
|
|
227
|
-
const columnNames = Array.from({
|
|
259
|
+
const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1}`);
|
|
228
260
|
columnNames.splice(0, 0, 'N-terminal');
|
|
229
261
|
columnNames.push('C-terminal');
|
|
230
262
|
|
|
@@ -76,8 +76,8 @@ export async function analyzePeptidesWidget(
|
|
|
76
76
|
if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
|
|
77
77
|
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
78
78
|
const options: {[key: string]: string} = {
|
|
79
|
-
'
|
|
80
|
-
'
|
|
79
|
+
'activityColumnName': activityColumnChoice.value.name,
|
|
80
|
+
'scaling': activityScalingMethod.value,
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
const peptides = new Peptides();
|
|
@@ -4,18 +4,18 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import $ from 'cash-dom';
|
|
5
5
|
import {model} from '../viewers/model';
|
|
6
6
|
import {splitAlignedPeptides} from '../utils/split-aligned';
|
|
7
|
+
import '../styles.css';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Manual sequence alignment widget.
|
|
10
11
|
*
|
|
11
12
|
* @param {DG.Column} alignedSequenceCol Aligned sequence column.
|
|
12
13
|
* @param {DG.DataFrame} currentDf Working table.
|
|
13
|
-
* @
|
|
14
|
+
* @return {DG.Widget} Widget for manual sequence alignment.
|
|
14
15
|
*/
|
|
15
16
|
export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf: DG.DataFrame) {
|
|
16
17
|
const sequenceInput = ui.textInput('', alignedSequenceCol.get(currentDf.currentRowIdx));
|
|
17
|
-
(sequenceInput.
|
|
18
|
-
(sequenceInput.input as HTMLElement).style.overflow = 'hidden';
|
|
18
|
+
$(sequenceInput.root).addClass('pep-textinput');
|
|
19
19
|
|
|
20
20
|
const applyChangesBtn = ui.button('Apply', async () => {
|
|
21
21
|
const newSequence = sequenceInput.value;
|
|
@@ -37,7 +37,7 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf:
|
|
|
37
37
|
() => sequenceInput.value = alignedSequenceCol.get(currentDf.currentRowIdx),
|
|
38
38
|
'Reset',
|
|
39
39
|
);
|
|
40
|
-
$(resetBtn).addClass('
|
|
40
|
+
$(resetBtn).addClass('pep-snippet-editor-icon pep-reset-icon');
|
|
41
41
|
|
|
42
|
-
return new DG.Widget(ui.divV([resetBtn, sequenceInput.root, applyChangesBtn], '
|
|
42
|
+
return new DG.Widget(ui.divV([resetBtn, sequenceInput.root, applyChangesBtn], 'pep-textarea-box'));
|
|
43
43
|
}
|