@datagrok/peptides 0.8.12 → 0.8.15
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 +5 -2
- package/dist/package-test.js +1060 -1557
- package/dist/package.js +958 -1492
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +120 -62
- package/package.json +16 -16
- package/src/model.ts +438 -387
- package/src/monomer-library.ts +31 -30
- package/src/package-test.ts +2 -3
- package/src/package.ts +56 -52
- package/src/tests/core.ts +63 -0
- package/src/tests/utils.ts +10 -7
- package/src/utils/cell-renderer.ts +25 -151
- package/src/utils/chem-palette.ts +3 -14
- package/src/utils/constants.ts +4 -0
- package/src/utils/filtering-statistics.ts +2 -2
- package/src/utils/misc.ts +29 -0
- package/src/utils/multiple-sequence-alignment.ts +5 -18
- package/src/utils/multivariate-analysis.ts +5 -8
- package/src/utils/peptide-similarity-space.ts +12 -9
- package/src/utils/types.ts +4 -0
- package/src/viewers/peptide-space-viewer.ts +18 -19
- package/src/viewers/sar-viewer.ts +32 -37
- package/src/viewers/stacked-barchart-viewer.ts +34 -34
- package/src/widgets/analyze-peptides.ts +53 -75
- package/src/widgets/distribution.ts +4 -9
- package/src/widgets/manual-alignment.ts +8 -12
- package/src/widgets/peptide-molecule.ts +48 -25
- package/src/widgets/subst-table.ts +43 -58
- package/src/workers/dimensionality-reducer.ts +8 -8
- package/{test-Peptides-414a1874a71a-2f1c6575.html → test-Peptides-e702a345ac13-2a8c8b59.html} +15 -17
- package/src/peptides.ts +0 -327
- package/src/semantics.ts +0 -5
- package/src/tests/peptides-tests.ts +0 -60
- package/src/utils/SAR-multiple-filter.ts +0 -439
- package/src/utils/SAR-multiple-selection.ts +0 -177
- package/src/viewers/logo-viewer.ts +0 -195
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-
|
|
5
|
-
import {
|
|
4
|
+
import * as C from '../utils/constants';
|
|
5
|
+
import {PeptidesModel} from '../model';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 3D representation widget of peptide molecule.
|
|
@@ -11,40 +11,63 @@ import {PeptidesController} from '../peptides';
|
|
|
11
11
|
* @param {string} pep Peptide string.
|
|
12
12
|
* @return {Promise<DG.Widget>} Widget.
|
|
13
13
|
*/
|
|
14
|
-
export async function peptideMoleculeWidget(pep: string): Promise<DG.Widget> {
|
|
14
|
+
export async function peptideMoleculeWidget(pep: string, currentTable: DG.DataFrame): Promise<DG.Widget> {
|
|
15
15
|
const pi = DG.TaskBarProgressIndicator.create('Creating NGL view');
|
|
16
|
+
const separator = currentTable.columns.bySemType(C.SEM_TYPES.ALIGNED_SEQUENCE)!.tags[C.TAGS.SEPARATOR];
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
let widgetHost;
|
|
19
|
+
let smiles = '';
|
|
20
|
+
let molfileStr = '';
|
|
21
|
+
try {
|
|
22
|
+
try {
|
|
23
|
+
const params = {table: currentTable};
|
|
24
|
+
const result = await grok.functions.call('Customerextensions:getPeptideStructure', params) as string[];
|
|
25
|
+
if (result.length !== 0) {
|
|
26
|
+
smiles = result[0];
|
|
27
|
+
molfileStr = result[1];
|
|
28
|
+
throw new Error(`Found structure in DB`);
|
|
29
|
+
}
|
|
20
30
|
|
|
31
|
+
smiles = getMolecule(pep, separator);
|
|
32
|
+
if (smiles == '')
|
|
33
|
+
throw new Error('Couldn\'t get smiles');
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
molfileStr = (await grok.functions.call('Peptides:SmiTo3D', {smiles})) as string;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.warn(e);
|
|
38
|
+
}
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
try {
|
|
41
|
+
molfileStr = molfileStr.replaceAll('\\n', '\n');
|
|
42
|
+
const stringBlob = new Blob([molfileStr], {type: 'text/plain'});
|
|
43
|
+
const nglHost = ui.div([], {classes: 'd4-ngl-viewer', id: 'ngl-3d-host'});
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
//@ts-ignore
|
|
46
|
+
const stage = new NGL.Stage(nglHost, {backgroundColor: 'white'});
|
|
47
|
+
//@ts-ignore
|
|
48
|
+
stage.loadFile(stringBlob, {ext: 'sdf'}).then(function(comp: NGL.StructureComponent) {
|
|
49
|
+
stage.setSize(300, 300);
|
|
50
|
+
comp.addRepresentation('ball+stick');
|
|
51
|
+
comp.autoView();
|
|
52
|
+
});
|
|
53
|
+
const sketch = grok.chem.svgMol(molfileStr);
|
|
54
|
+
const panel = ui.divH([sketch]);
|
|
38
55
|
|
|
56
|
+
widgetHost = ui.div([panel, nglHost]);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
widgetHost = ui.divText('Couldn\'t get peptide structure');
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
widgetHost = ui.divText('Couldn\'t get peptide structure');
|
|
62
|
+
}
|
|
39
63
|
pi.close();
|
|
40
|
-
|
|
41
|
-
return new DG.Widget(ui.div([panel, nglHost]));
|
|
64
|
+
return new DG.Widget(widgetHost);
|
|
42
65
|
}
|
|
43
66
|
|
|
44
|
-
export function getMolecule(pep: string): string {
|
|
45
|
-
const split = pep.split(
|
|
67
|
+
export function getMolecule(pep: string, separator: string): string {
|
|
68
|
+
const split = pep.split(separator);
|
|
46
69
|
const mols = [];
|
|
47
|
-
const chemPalette =
|
|
70
|
+
const chemPalette = PeptidesModel.chemPalette;
|
|
48
71
|
for (let i = 1; i < split.length - 1; i++) {
|
|
49
72
|
if (split[i] in chemPalette.AASmiles) {
|
|
50
73
|
const aar = chemPalette.AASmiles[split[i]];
|
|
@@ -1,73 +1,58 @@
|
|
|
1
1
|
import * as ui from 'datagrok-api/ui';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
import
|
|
3
|
+
import * as C from '../utils/constants';
|
|
4
|
+
import * as type from '../utils/types';
|
|
5
|
+
import {PeptidesModel} from '../model';
|
|
4
6
|
|
|
5
7
|
export async function substitutionsWidget(table: DG.DataFrame): Promise<DG.Widget> {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
8
|
+
const model = await PeptidesModel.getInstance(table);
|
|
9
|
+
const substInfo = model.substitutionsInfo;
|
|
10
|
+
const currentCell = model.getCurrentAARandPos();
|
|
9
11
|
|
|
10
|
-
if (
|
|
12
|
+
if (currentCell.aar === currentCell.pos)
|
|
11
13
|
return new DG.Widget(ui.label('No substitution table generated'));
|
|
12
14
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let aminoFrom = '';
|
|
18
|
-
let aminoTo = '';
|
|
19
|
-
const initialCol: DG.Column = substTable.getCol('Initial');
|
|
20
|
-
const substitutedCol: DG.Column = substTable.getCol('Substituted');
|
|
21
|
-
|
|
22
|
-
initialCol.semType = 'alignedSequenceDifference';
|
|
23
|
-
initialCol.name = 'Substitution';
|
|
24
|
-
// substTable.columns.remove('Substituted');
|
|
25
|
-
// const substCol = table.getCol('Substitution');
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < dfRowCount; ++i) {
|
|
28
|
-
// const [from, to] = substCol!.get(i).split('#');
|
|
29
|
-
const from = initialCol.get(i);
|
|
30
|
-
const to = substitutedCol.get(i);
|
|
31
|
-
const aminosFrom: [] = from.split('-');
|
|
32
|
-
const aminosTo: [] = to.split('-');
|
|
33
|
-
|
|
34
|
-
for (let j = 0; j < aminosFrom.length; ++j) {
|
|
35
|
-
if (aminosFrom[j] != aminosTo[j]) {
|
|
36
|
-
const idx = `${getAmino(aminosFrom[j])}#${getAmino(aminosTo[j])}`;
|
|
15
|
+
const substitutionsMap =
|
|
16
|
+
substInfo.get(currentCell.aar)?.get(currentCell.pos) as Map<number, type.UTypedArray> | undefined;
|
|
17
|
+
if (typeof substitutionsMap === 'undefined')
|
|
18
|
+
return new DG.Widget(ui.label('No substitution table generated'));
|
|
37
19
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
20
|
+
const substitutionsArray: string[] = [];
|
|
21
|
+
const deltaArray: number[] = [];
|
|
22
|
+
const substitutedToArray: string[] = [];
|
|
23
|
+
// const alignedSeqCol = table.getCol(C.COLUMNS_NAMES.ALIGNED_SEQUENCE);
|
|
24
|
+
// const activityScaledCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
25
|
+
const alignedSeqCol = table.columns.bySemType(C.SEM_TYPES.ALIGNED_SEQUENCE)!;
|
|
26
|
+
const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
27
|
+
const posCol = table.getCol(currentCell.pos);
|
|
28
|
+
for (const [referenceIdx, indexArray] of substitutionsMap.entries()) {
|
|
29
|
+
const baseSequence = alignedSeqCol.get(referenceIdx);
|
|
30
|
+
const baseActivity = activityScaledCol.get(referenceIdx);
|
|
31
|
+
for (const subIdx of indexArray) {
|
|
32
|
+
substitutionsArray.push(`${baseSequence}#${alignedSeqCol.get(subIdx)}`);
|
|
33
|
+
deltaArray.push(baseActivity - activityScaledCol.get(subIdx));
|
|
34
|
+
substitutedToArray.push(posCol.get(subIdx));
|
|
42
35
|
}
|
|
43
36
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
substTable.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
aminoInputTo.onInput(() => {
|
|
58
|
-
aminoTo = getAmino(aminoInputTo.value);
|
|
59
|
-
const toKey = `${aminoFrom}#${aminoTo}`;
|
|
60
|
-
if (toKey in fromToMap)
|
|
61
|
-
substTable.selection.copyFrom(fromToMap[toKey]);
|
|
37
|
+
const substCol = DG.Column.fromStrings('Substiutions', substitutionsArray);
|
|
38
|
+
substCol.semType = C.SEM_TYPES.ALIGNED_SEQUENCE_DIFFERENCE;
|
|
39
|
+
const toColName = '~to';
|
|
40
|
+
const hiddenSubstToAarCol = DG.Column.fromStrings(toColName, substitutedToArray);
|
|
41
|
+
const substTable =
|
|
42
|
+
DG.DataFrame.fromColumns([substCol, DG.Column.fromList('double', 'Delta', deltaArray), hiddenSubstToAarCol]);
|
|
43
|
+
|
|
44
|
+
const aminoToInput = ui.stringInput('Substituted to:', '', () => {
|
|
45
|
+
const substitutedToAar = aminoToInput.stringValue;
|
|
46
|
+
if (substitutedToAar != '')
|
|
47
|
+
substTable.filter.init((idx) => hiddenSubstToAarCol.get(idx) === substitutedToAar);
|
|
48
|
+
else
|
|
49
|
+
substTable.filter.setAll(true);
|
|
62
50
|
});
|
|
63
51
|
|
|
64
52
|
const grid = substTable.plot.grid();
|
|
65
53
|
grid.props.allowEdit = false;
|
|
66
|
-
grid.root
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function getAmino(amino: string): string {
|
|
72
|
-
return amino === '' ? '-' : amino;
|
|
54
|
+
const gridRoot = grid.root;
|
|
55
|
+
gridRoot.style.width = 'auto';
|
|
56
|
+
gridRoot.style.height = '150px';
|
|
57
|
+
return new DG.Widget(ui.divV([aminoToInput.root, gridRoot]));
|
|
73
58
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {DimensionalityReducer, KnownMethods} from '@datagrok-libraries/ml/src/reduce-dimensionality';
|
|
2
2
|
import {KnownMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
3
|
-
import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Worker thread receiving data function.
|
|
@@ -8,23 +7,24 @@ import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
|
8
7
|
* @param {any[]} columnData Samples to process.
|
|
9
8
|
* @param {string} method Embedding method.
|
|
10
9
|
* @param {string} measure Distance metric.
|
|
11
|
-
* @param {
|
|
12
|
-
* @return {
|
|
10
|
+
* @param {any} options Options to pass to algorithm.
|
|
11
|
+
* @return {any} Embedding (and distance matrix where applicable).
|
|
13
12
|
*/
|
|
14
|
-
function onMessage(columnData: any[], method: KnownMethods, measure: KnownMetrics,
|
|
13
|
+
function onMessage(columnData: any[], method: KnownMethods, measure: KnownMetrics, options: any): any {
|
|
15
14
|
const reducer = new DimensionalityReducer(
|
|
16
15
|
columnData,
|
|
17
16
|
method,
|
|
18
17
|
measure,
|
|
19
|
-
|
|
18
|
+
options,
|
|
20
19
|
);
|
|
21
20
|
return reducer.transform(true);
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
self.onmessage = ({data: {columnData, method, measure,
|
|
25
|
-
const embedding = onMessage(columnData, method, measure,
|
|
23
|
+
self.onmessage = ({data: {columnData, method, measure, options}}): void => {
|
|
24
|
+
const embedding = onMessage(columnData, method, measure, options);
|
|
26
25
|
self.postMessage({
|
|
27
|
-
|
|
26
|
+
distance: embedding.distance,
|
|
27
|
+
embedding: embedding.embedding,
|
|
28
28
|
});
|
|
29
29
|
};
|
|
30
30
|
|
package/{test-Peptides-414a1874a71a-2f1c6575.html → test-Peptides-e702a345ac13-2a8c8b59.html}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=
|
|
1
|
+
<html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=e702a345ac13. Commit 2a8c8b59.</title><style type="text/css">html,
|
|
2
2
|
body {
|
|
3
3
|
font-family: Arial, Helvetica, sans-serif;
|
|
4
4
|
font-size: 1rem;
|
|
@@ -229,21 +229,14 @@ header {
|
|
|
229
229
|
font-size: 1rem;
|
|
230
230
|
padding: 0 0.5rem;
|
|
231
231
|
}
|
|
232
|
-
</style></head><body><div id="jesthtml-content"><header><h1 id="title">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
at
|
|
237
|
-
at
|
|
238
|
-
at
|
|
239
|
-
at
|
|
240
|
-
at runTest (/home/runner/work/public/public/packages/Peptides/node_modules/jest-runner/build/runTest.js:475:34)
|
|
241
|
-
at TestRunner.runTests (/home/runner/work/public/public/packages/Peptides/node_modules/jest-runner/build/index.js:101:12)
|
|
242
|
-
at TestScheduler.scheduleTests (/home/runner/work/public/public/packages/Peptides/node_modules/@jest/core/build/TestScheduler.js:333:13)
|
|
243
|
-
at runJest (/home/runner/work/public/public/packages/Peptides/node_modules/@jest/core/build/runJest.js:404:19)
|
|
244
|
-
at _run10000 (/home/runner/work/public/public/packages/Peptides/node_modules/@jest/core/build/cli/index.js:320:7)
|
|
245
|
-
at runCLI (/home/runner/work/public/public/packages/Peptides/node_modules/@jest/core/build/cli/index.js:173:3)
|
|
246
|
-
at Object.run (/home/runner/work/public/public/packages/Peptides/node_modules/jest-cli/build/cli/index.js:155:37)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.<anonymous> (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:62:11)
|
|
232
|
+
</style></head><body><div id="jesthtml-content"><header><h1 id="title">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=e702a345ac13. Commit 2a8c8b59.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-06-06 21:05:18</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts</div><div class="suite-time warn">105.848s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">95.396s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: expect(received).toBe(expected) // Object.is equality
|
|
233
|
+
|
|
234
|
+
Expected: false
|
|
235
|
+
Received: true
|
|
236
|
+
at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:49:20
|
|
237
|
+
at Generator.next (<anonymous>)
|
|
238
|
+
at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:24:58)
|
|
239
|
+
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.<anonymous> (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:62:11)
|
|
247
240
|
at Generator.next (<anonymous>)
|
|
248
241
|
at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:24:58)
|
|
249
242
|
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:24:11
|
|
@@ -253,4 +246,9 @@ Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long
|
|
|
253
246
|
at Object.<anonymous>.__awaiter (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:23:12)
|
|
254
247
|
at Object.<anonymous> (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:22:23)
|
|
255
248
|
at Promise.then.completed (/home/runner/work/public/public/packages/Peptides/node_modules/jest-circus/build/utils.js:391:28)
|
|
256
|
-
at new Promise (<anonymous>)</pre><pre class="suite-consolelog-item-message">Testing Peptides package</pre></div
|
|
249
|
+
at new Promise (<anonymous>)</pre><pre class="suite-consolelog-item-message">Testing Peptides package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:47:11
|
|
250
|
+
at Generator.next (<anonymous>)
|
|
251
|
+
at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:24:58)
|
|
252
|
+
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Core.Start analysis: simple: Operation caused an exception (FileSystemException: Cannot open file, path = '/home/grok/data/prod/packages/data/Peptides/HELMMonomers_June10.sdf' (OS Error: No such file or directory, errno = 2))
|
|
253
|
+
Core.Start analysis: сomplex: Operation caused an exception (FileSystemException: Cannot open file, path = '/home/grok/data/prod/packages/data/Peptides/HELMMonomers_June10.sdf' (OS Error: No such file or directory, errno = 2))
|
|
254
|
+
</pre></div></div></div></div></body></html>
|
package/src/peptides.ts
DELETED
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import * as grok from 'datagrok-api/grok';
|
|
2
|
-
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
import {PeptidesModel} from './model';
|
|
4
|
-
import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
|
|
5
|
-
import {ChemPalette} from './utils/chem-palette';
|
|
6
|
-
import {Observable} from 'rxjs';
|
|
7
|
-
import {MonomerLibrary} from './monomer-library';
|
|
8
|
-
import {_package} from './package';
|
|
9
|
-
import {setAARRenderer} from './utils/cell-renderer';
|
|
10
|
-
import * as C from './utils/constants';
|
|
11
|
-
import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
|
|
12
|
-
import { FilteringStatistics } from './utils/filtering-statistics';
|
|
13
|
-
|
|
14
|
-
type viewerTypes = SARViewer | SARViewerVertical;
|
|
15
|
-
export class PeptidesController {
|
|
16
|
-
private static _controllerName: string = 'peptidesController';
|
|
17
|
-
private helpUrl = '/help/domains/bio/peptides.md';
|
|
18
|
-
|
|
19
|
-
private _model: PeptidesModel;
|
|
20
|
-
sarViewer!: SARViewer;
|
|
21
|
-
sarViewerVertical!: SARViewerVertical;
|
|
22
|
-
isInitialized = false;
|
|
23
|
-
|
|
24
|
-
private constructor(dataFrame: DG.DataFrame) {
|
|
25
|
-
this._model = PeptidesModel.getInstance(dataFrame);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static async getInstance(dataFrame: DG.DataFrame): Promise<PeptidesController> {
|
|
29
|
-
dataFrame.temp[PeptidesController.controllerName] ??= new PeptidesController(dataFrame);
|
|
30
|
-
if (dataFrame.temp[MonomerLibrary.id] === null) {
|
|
31
|
-
const sdf = await _package.files.readAsText('HELMMonomers_June10.sdf');
|
|
32
|
-
dataFrame.temp[MonomerLibrary.id] ??= new MonomerLibrary(sdf);
|
|
33
|
-
}
|
|
34
|
-
return dataFrame.temp[PeptidesController.controllerName];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static get controllerName() {return PeptidesController._controllerName;}
|
|
38
|
-
|
|
39
|
-
get dataFrame() {return this._model.dataFrame;}
|
|
40
|
-
|
|
41
|
-
static setAARRenderer(col: DG.Column, grid: DG.Grid) {
|
|
42
|
-
return setAARRenderer(col, grid);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
get onStatsDataFrameChanged(): Observable<DG.DataFrame> {return this._model.onStatsDataFrameChanged;}
|
|
46
|
-
|
|
47
|
-
get onSARGridChanged(): Observable<DG.Grid> {return this._model.onSARGridChanged;}
|
|
48
|
-
|
|
49
|
-
get onSARVGridChanged(): Observable<DG.Grid> {return this._model.onSARVGridChanged;}
|
|
50
|
-
|
|
51
|
-
// get onGroupMappingChanged(): Observable<StringDictionary> {return this._model.onGroupMappingChanged;}
|
|
52
|
-
|
|
53
|
-
get onSubstTableChanged(): Observable<DG.DataFrame> {return this._model.onSubstTableChanged;}
|
|
54
|
-
|
|
55
|
-
async updateDefault() {await this._model.updateDefault();}
|
|
56
|
-
|
|
57
|
-
get sarGrid() {return this._model._sarGrid;}
|
|
58
|
-
|
|
59
|
-
get sarVGrid() {return this._model._sarVGrid;}
|
|
60
|
-
|
|
61
|
-
get sourceGrid() {return this._model._sourceGrid!; }
|
|
62
|
-
|
|
63
|
-
async updateData(
|
|
64
|
-
activityScaling?: string, sourceGrid?: DG.Grid, twoColorMode?: boolean, activityLimit?: number,
|
|
65
|
-
maxSubstitutions?: number, isSubstitutionOn?: boolean, filterMode?: boolean,
|
|
66
|
-
) {
|
|
67
|
-
filterMode ??= false;
|
|
68
|
-
await this._model.updateData(
|
|
69
|
-
activityScaling, sourceGrid, twoColorMode, activityLimit, maxSubstitutions, isSubstitutionOn, filterMode);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
getSubstitutions() {
|
|
73
|
-
return this._model.getSubstitutionTable();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
static async scaleActivity(
|
|
77
|
-
activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
|
|
78
|
-
): Promise<[DG.DataFrame, string]> {
|
|
79
|
-
// const df = sourceGrid.dataFrame!;
|
|
80
|
-
let currentActivityColName = originalActivityName ?? C.COLUMNS_NAMES.ACTIVITY;
|
|
81
|
-
const flag = (df.columns as DG.ColumnList).names().includes(currentActivityColName) &&
|
|
82
|
-
currentActivityColName === originalActivityName;
|
|
83
|
-
currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
|
|
84
|
-
const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
|
|
85
|
-
|
|
86
|
-
let formula = '${' + currentActivityColName + '}';
|
|
87
|
-
let newColName = 'activity'; //originalActivityName ?? df.temp[C.COLUMNS_NAMES.ACTIVITY] ?? currentActivityColName;
|
|
88
|
-
switch (activityScaling) {
|
|
89
|
-
case 'none':
|
|
90
|
-
break;
|
|
91
|
-
case 'lg':
|
|
92
|
-
formula = `Log10(${formula})`;
|
|
93
|
-
newColName = `Log10(${newColName})`;
|
|
94
|
-
break;
|
|
95
|
-
case '-lg':
|
|
96
|
-
formula = `-1*Log10(${formula})`;
|
|
97
|
-
newColName = `-Log10(${newColName})`;
|
|
98
|
-
break;
|
|
99
|
-
default:
|
|
100
|
-
throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
await (tempDf.columns as DG.ColumnList).addNewCalculated(C.COLUMNS_NAMES.ACTIVITY_SCALED, formula);
|
|
104
|
-
df.tags['scaling'] = activityScaling;
|
|
105
|
-
|
|
106
|
-
return [tempDf, newColName];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
get originalActivityColumnName(): string {return this.dataFrame.temp[C.COLUMNS_NAMES.ACTIVITY];}
|
|
110
|
-
|
|
111
|
-
get substTooltipData() {return this._model.substTooltipData;}
|
|
112
|
-
|
|
113
|
-
static splitAlignedPeptides(peptideColumn: DG.Column, filter: boolean = true): [DG.DataFrame, number[]] {
|
|
114
|
-
const splitPeptidesArray: string[][] = [];
|
|
115
|
-
let currentSplitPeptide: string[];
|
|
116
|
-
let modeMonomerCount = 0;
|
|
117
|
-
let currentLength;
|
|
118
|
-
const colLength = peptideColumn.length;
|
|
119
|
-
|
|
120
|
-
// splitting data
|
|
121
|
-
const monomerLengths: {[index: string]: number} = {};
|
|
122
|
-
for (let i = 0; i < colLength; i++) {
|
|
123
|
-
currentSplitPeptide = peptideColumn.get(i).split('-').map((value: string) => value ? value : '-');
|
|
124
|
-
splitPeptidesArray.push(currentSplitPeptide);
|
|
125
|
-
currentLength = currentSplitPeptide.length;
|
|
126
|
-
monomerLengths[currentLength + ''] =
|
|
127
|
-
monomerLengths[currentLength + ''] ? monomerLengths[currentLength + ''] + 1 : 1;
|
|
128
|
-
}
|
|
129
|
-
//@ts-ignore: what I do here is converting string to number the most effective way I could find. parseInt is slow
|
|
130
|
-
modeMonomerCount = 1 * Object.keys(monomerLengths).reduce((a, b) => monomerLengths[a] > monomerLengths[b] ? a : b);
|
|
131
|
-
|
|
132
|
-
// making sure all of the sequences are of the same size
|
|
133
|
-
// and marking invalid sequences
|
|
134
|
-
let nTerminal: string;
|
|
135
|
-
const invalidIndexes: number[] = [];
|
|
136
|
-
let splitColumns: string[][] = Array.from({length: modeMonomerCount}, (_) => []);
|
|
137
|
-
modeMonomerCount--; // minus N-terminal
|
|
138
|
-
for (let i = 0; i < colLength; i++) {
|
|
139
|
-
currentSplitPeptide = splitPeptidesArray[i];
|
|
140
|
-
nTerminal = currentSplitPeptide.pop()!; // it is guaranteed that there will be at least one element
|
|
141
|
-
currentLength = currentSplitPeptide.length;
|
|
142
|
-
if (currentLength !== modeMonomerCount)
|
|
143
|
-
invalidIndexes.push(i);
|
|
144
|
-
|
|
145
|
-
for (let j = 0; j < modeMonomerCount; j++)
|
|
146
|
-
splitColumns[j].push(j < currentLength ? currentSplitPeptide[j] : '-');
|
|
147
|
-
|
|
148
|
-
splitColumns[modeMonomerCount].push(nTerminal);
|
|
149
|
-
}
|
|
150
|
-
modeMonomerCount--; // minus C-terminal
|
|
151
|
-
|
|
152
|
-
//create column names list
|
|
153
|
-
const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1 }`);
|
|
154
|
-
columnNames.splice(0, 0, 'Nterminal');
|
|
155
|
-
columnNames.push('Cterminal');
|
|
156
|
-
|
|
157
|
-
// filter out the columns with the same values
|
|
158
|
-
if (filter) {
|
|
159
|
-
splitColumns = splitColumns.filter((positionArray, index) => {
|
|
160
|
-
const isRetained = new Set(positionArray).size > 1;
|
|
161
|
-
if (!isRetained)
|
|
162
|
-
columnNames.splice(index, 1);
|
|
163
|
-
|
|
164
|
-
return isRetained;
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return [
|
|
169
|
-
DG.DataFrame.fromColumns(splitColumns.map((positionArray, index) => {
|
|
170
|
-
return DG.Column.fromList('string', columnNames[index], positionArray);
|
|
171
|
-
})),
|
|
172
|
-
invalidIndexes,
|
|
173
|
-
];
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
static get chemPalette() { return ChemPalette; }
|
|
177
|
-
|
|
178
|
-
assertVar(variable: string, init = false): boolean {
|
|
179
|
-
//@ts-ignore
|
|
180
|
-
let foundVariable: any = this[variable];
|
|
181
|
-
if (!foundVariable && init) {
|
|
182
|
-
//@ts-ignore
|
|
183
|
-
this[variable] = foundVariable = this.dataFrame.temp[variable];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const assertionResult = foundVariable ? true : false
|
|
187
|
-
if (init && !assertionResult)
|
|
188
|
-
throw new Error(`Variable assertion error: variable '${variable}' is not found in dataFrame`);
|
|
189
|
-
|
|
190
|
-
return assertionResult;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
assertVariables(variables: string[], init = false) {
|
|
194
|
-
let result = true;
|
|
195
|
-
for (const variable of variables)
|
|
196
|
-
result &&= this.assertVar(variable, init);
|
|
197
|
-
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
syncProperties(isSourceSAR = true) {
|
|
202
|
-
this.assertVariables(['sarViewer', 'sarViewerVertical'], true);
|
|
203
|
-
const sourceViewer = isSourceSAR ? this.sarViewer : this.sarViewerVertical;
|
|
204
|
-
const targetViewer = isSourceSAR ? this.sarViewerVertical : this.sarViewer;
|
|
205
|
-
const properties = sourceViewer.props.getProperties();
|
|
206
|
-
for (const property of properties)
|
|
207
|
-
targetViewer.props.set(property.name, property.get(sourceViewer));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
modifyOrCreateSplitCol(aar: string, position: string, notify: boolean = true) {
|
|
211
|
-
this._model.modifyOrCreateSplitCol(aar, position);
|
|
212
|
-
if (notify)
|
|
213
|
-
this._model.fireBitsetChanged();
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
setSARGridCellAt(aar: string, position: string) {
|
|
217
|
-
const sarDf = this.sarGrid.dataFrame;
|
|
218
|
-
const aarCol = sarDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
219
|
-
const aarColLen = aarCol.length;
|
|
220
|
-
let index = -1;
|
|
221
|
-
for (let i = 0; i < aarColLen; i++) {
|
|
222
|
-
if (aarCol.get(i) === aar) {
|
|
223
|
-
index = i;
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
position = position === C.CATEGORIES.ALL ? C.COLUMNS_NAMES.AMINO_ACID_RESIDUE : position;
|
|
228
|
-
sarDf.currentCell = sarDf.cell(index, position);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Class initializer
|
|
233
|
-
*
|
|
234
|
-
* @param {DG.Grid} sourceGrid Working talbe grid.
|
|
235
|
-
* @param {DG.TableView} currentView Working view.
|
|
236
|
-
* @param {DG.DataFrame} currentDf Working table.
|
|
237
|
-
* @param {StringDictionary} options SAR viewer options
|
|
238
|
-
* @param {DG.Column} col Aligned sequences column.
|
|
239
|
-
* @memberof Peptides
|
|
240
|
-
*/
|
|
241
|
-
async init(table: DG.DataFrame) {
|
|
242
|
-
if (this.isInitialized)
|
|
243
|
-
return;
|
|
244
|
-
this.isInitialized = true;
|
|
245
|
-
//calculate initial stats
|
|
246
|
-
const stats = new FilteringStatistics();
|
|
247
|
-
const activityScaledCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
248
|
-
stats.setData(activityScaledCol.getRawData() as Float32Array);
|
|
249
|
-
stats.setMask(table.selection);
|
|
250
|
-
table.temp[C.STATS] = stats;
|
|
251
|
-
|
|
252
|
-
//set up views
|
|
253
|
-
let currentView = grok.shell.v as DG.TableView ;
|
|
254
|
-
if (currentView.dataFrame.tags['isPeptidesAnalysis'] !== 'true')
|
|
255
|
-
currentView = grok.shell.addTableView(table);
|
|
256
|
-
const sourceGrid = currentView.grid;
|
|
257
|
-
sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!.name = table.temp[C.COLUMNS_NAMES.ACTIVITY_SCALED];
|
|
258
|
-
sourceGrid.columns.setOrder([table.temp[C.COLUMNS_NAMES.ACTIVITY_SCALED]]);
|
|
259
|
-
|
|
260
|
-
this.dataFrame.temp[C.EMBEDDING_STATUS] = false;
|
|
261
|
-
function adjustCellSize(grid: DG.Grid) {
|
|
262
|
-
const colNum = grid.columns.length;
|
|
263
|
-
for (let i = 0; i < colNum; ++i) {
|
|
264
|
-
const iCol = grid.columns.byIndex(i)!;
|
|
265
|
-
iCol.width = isNaN(parseInt(iCol.name)) ? 50 : 40;
|
|
266
|
-
}
|
|
267
|
-
grid.props.rowHeight = 20;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
for (let i = 0; i < sourceGrid.columns.length; i++) {
|
|
271
|
-
const aarCol = sourceGrid.columns.byIndex(i);
|
|
272
|
-
if (aarCol && aarCol.name && aarCol.column?.semType !== C.SEM_TYPES.AMINO_ACIDS &&
|
|
273
|
-
aarCol.name !== this.dataFrame.temp[C.COLUMNS_NAMES.ACTIVITY_SCALED]
|
|
274
|
-
)
|
|
275
|
-
sourceGrid.columns.byIndex(i)!.visible = false;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const options = {scaling: table.tags['scaling']};
|
|
279
|
-
await this.updateData(table.tags['scaling'], sourceGrid, false, 1, 2, false, false);
|
|
280
|
-
|
|
281
|
-
const dockManager = currentView.dockManager;
|
|
282
|
-
|
|
283
|
-
this.dataFrame.temp['sarViewer'] = this.sarViewer =
|
|
284
|
-
await this.dataFrame.plot.fromType('peptide-sar-viewer', options) as SARViewer;
|
|
285
|
-
this.sarViewer.helpUrl = this.helpUrl;
|
|
286
|
-
|
|
287
|
-
this.dataFrame.temp['sarViewerVertical'] = this.sarViewerVertical =
|
|
288
|
-
await this.dataFrame.plot.fromType('peptide-sar-viewer-vertical', options) as SARViewerVertical;
|
|
289
|
-
this.sarViewerVertical.helpUrl = this.helpUrl;
|
|
290
|
-
|
|
291
|
-
const sarViewersGroup: viewerTypes[] = [this.sarViewer, this.sarViewerVertical];
|
|
292
|
-
|
|
293
|
-
const peptideSpaceViewerOptions = {method: 't-SNE', measure: 'Levenshtein', cyclesCount: 100};
|
|
294
|
-
const peptideSpaceViewer =
|
|
295
|
-
await this.dataFrame.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
|
|
296
|
-
dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space Viewer');
|
|
297
|
-
|
|
298
|
-
dockViewers(sarViewersGroup, DG.DOCK_TYPE.RIGHT, dockManager, DG.DOCK_TYPE.DOWN);
|
|
299
|
-
|
|
300
|
-
sourceGrid.props.allowEdit = false;
|
|
301
|
-
adjustCellSize(sourceGrid);
|
|
302
|
-
|
|
303
|
-
// this._model._sarGrid.invalidate();
|
|
304
|
-
// this._model._sarVGrid.invalidate();
|
|
305
|
-
this._model.invalidateGrids();
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
invalidateSourceGrid() { this.sourceGrid.invalidate(); }
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function dockViewers(
|
|
312
|
-
viewerList: viewerTypes[], attachDirection: DG.DockType, dockManager: DG.DockManager,
|
|
313
|
-
initialAttachDirection?: DG.DockType): DG.DockNode[] | null {
|
|
314
|
-
const viewerListLength = viewerList.length;
|
|
315
|
-
if (viewerListLength === 0)
|
|
316
|
-
return null;
|
|
317
|
-
|
|
318
|
-
let currentViewer = viewerList[0];
|
|
319
|
-
const nodeList = [dockManager.dock(currentViewer, initialAttachDirection, null, currentViewer.name ?? '')];
|
|
320
|
-
const ratio = 1 / viewerListLength;
|
|
321
|
-
|
|
322
|
-
for (let i = 1; i < viewerListLength; i++) {
|
|
323
|
-
currentViewer = viewerList[i];
|
|
324
|
-
nodeList.push(dockManager.dock(currentViewer, attachDirection, nodeList[i - 1], currentViewer.name ?? '', ratio));
|
|
325
|
-
}
|
|
326
|
-
return nodeList;
|
|
327
|
-
}
|