@datagrok/peptides 1.17.4 → 1.17.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/CHANGELOG.md +9 -1
- package/dist/23.js +2 -0
- package/dist/282.js +2 -0
- package/dist/301.js +2 -0
- package/dist/356.js +2 -2
- package/dist/40.js +2 -0
- package/dist/427.js +2 -0
- package/dist/436.js +2 -2
- package/dist/796.js +2 -2
- package/dist/997.js +2 -0
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +2 -2
- package/src/model.ts +99 -2
- package/src/package-test.ts +4 -0
- package/src/tests/core.ts +13 -23
- package/src/tests/viewers.ts +2 -1
- package/src/tests/widgets.ts +4 -2
- package/src/utils/cell-renderer.ts +6 -2
- package/src/utils/misc.ts +12 -0
- package/src/utils/types.ts +11 -0
- package/src/viewers/sar-viewer.ts +12 -3
- package/src/widgets/peptides.ts +23 -2
- package/src/widgets/settings.ts +87 -6
- package/webpack.config.js +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
3
|
"friendlyName": "Peptides",
|
|
4
|
-
"version": "1.17.
|
|
4
|
+
"version": "1.17.6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Davit Rizhinashvili",
|
|
7
7
|
"email": "drizhinashvili@datagrok.ai"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@datagrok-libraries/bio": "^5.39.14",
|
|
17
|
-
"@datagrok-libraries/ml": "^6.4.
|
|
17
|
+
"@datagrok-libraries/ml": "^6.4.10",
|
|
18
18
|
"@datagrok-libraries/statistics": "^1.2.11",
|
|
19
19
|
"@datagrok-libraries/utils": "^4.1.36",
|
|
20
20
|
"@datagrok-libraries/tutorials": "^1.3.11",
|
package/src/model.ts
CHANGED
|
@@ -51,6 +51,8 @@ import {showMonomerTooltip} from './utils/tooltips';
|
|
|
51
51
|
import {AggregationColumns, MonomerPositionStats} from './utils/statistics';
|
|
52
52
|
import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
|
|
53
53
|
import {getDbscanWorker} from '@datagrok-libraries/math';
|
|
54
|
+
import {markovCluster} from '@datagrok-libraries/ml/src/MCL/clustering-view';
|
|
55
|
+
import {DistanceAggregationMethods} from '@datagrok-libraries/ml/src/distance-matrix/types';
|
|
54
56
|
|
|
55
57
|
export enum VIEWER_TYPE {
|
|
56
58
|
MONOMER_POSITION = 'Monomer-Position',
|
|
@@ -99,6 +101,8 @@ export class PeptidesModel {
|
|
|
99
101
|
accordionSource: VIEWER_TYPE | null = null;
|
|
100
102
|
// sequence space viewer
|
|
101
103
|
_sequenceSpaceViewer: DG.ScatterPlotViewer | null = null;
|
|
104
|
+
//MCL viewer
|
|
105
|
+
_mclViewer: DG.ScatterPlotViewer | null = null;
|
|
102
106
|
/**
|
|
103
107
|
* @param {DG.DataFrame}dataFrame - DataFrame to use for analysis
|
|
104
108
|
*/
|
|
@@ -151,6 +155,7 @@ export class PeptidesModel {
|
|
|
151
155
|
// Peptides analysis settings
|
|
152
156
|
_settings: type.PeptidesSettings | null = null;
|
|
153
157
|
_sequenceSpaceCols: string[] = [];
|
|
158
|
+
_mclCols: string[] = [];
|
|
154
159
|
|
|
155
160
|
/**
|
|
156
161
|
* @return {type.PeptidesSettings}- Peptides analysis settings
|
|
@@ -185,6 +190,9 @@ export class PeptidesModel {
|
|
|
185
190
|
case 'showDendrogram':
|
|
186
191
|
updateVars.add('dendrogram');
|
|
187
192
|
break;
|
|
193
|
+
case 'showSequenceSpace':
|
|
194
|
+
updateVars.add('showSequenceSpace');
|
|
195
|
+
break;
|
|
188
196
|
case 'showLogoSummaryTable':
|
|
189
197
|
updateVars.add('logoSummaryTable');
|
|
190
198
|
break;
|
|
@@ -199,6 +207,10 @@ export class PeptidesModel {
|
|
|
199
207
|
break;
|
|
200
208
|
case 'sequenceSpaceParams':
|
|
201
209
|
updateVars.add('sequenceSpaceParams');
|
|
210
|
+
break;
|
|
211
|
+
case 'mclSettings':
|
|
212
|
+
updateVars.add('mclSettings');
|
|
213
|
+
break;
|
|
202
214
|
}
|
|
203
215
|
}
|
|
204
216
|
// Write updated settings
|
|
@@ -216,6 +228,8 @@ export class PeptidesModel {
|
|
|
216
228
|
updateVars.add('clusterParams');
|
|
217
229
|
}
|
|
218
230
|
}
|
|
231
|
+
if (updateVars.has('sequenceSpaceParams'))
|
|
232
|
+
updateVars.delete('clusterParams');
|
|
219
233
|
|
|
220
234
|
// Apply new settings
|
|
221
235
|
for (const variable of updateVars) {
|
|
@@ -258,11 +272,16 @@ export class PeptidesModel {
|
|
|
258
272
|
mpr.render();
|
|
259
273
|
break;
|
|
260
274
|
case 'sequenceSpaceParams':
|
|
261
|
-
|
|
275
|
+
case 'showSequenceSpace':
|
|
276
|
+
if (this.settings!.showSequenceSpace)
|
|
277
|
+
this.addSequenceSpace({clusterEmbeddings: this.settings!.sequenceSpaceParams?.clusterEmbeddings});
|
|
262
278
|
break;
|
|
263
279
|
case 'clusterParams':
|
|
264
280
|
this.clusterEmbeddings();
|
|
265
281
|
break;
|
|
282
|
+
case 'mclSettings':
|
|
283
|
+
this.addMCLClusters();
|
|
284
|
+
break;
|
|
266
285
|
}
|
|
267
286
|
}
|
|
268
287
|
}
|
|
@@ -1170,6 +1189,67 @@ export class PeptidesModel {
|
|
|
1170
1189
|
gridCol && (gridCol.visible = false);
|
|
1171
1190
|
}
|
|
1172
1191
|
|
|
1192
|
+
async addMCLClusters(): Promise<void> {
|
|
1193
|
+
if (this._mclViewer !== null) {
|
|
1194
|
+
try {
|
|
1195
|
+
this._mclViewer?.detach();
|
|
1196
|
+
this._mclViewer?.close();
|
|
1197
|
+
} catch (_) {}
|
|
1198
|
+
}
|
|
1199
|
+
if (this._mclCols.length !== 0)
|
|
1200
|
+
this._mclCols.forEach((col) => this.df.columns.remove(col));
|
|
1201
|
+
this._mclCols = [];
|
|
1202
|
+
const seqCol = this.df.getCol(this.settings!.sequenceColumnName!);
|
|
1203
|
+
this.settings!.mclSettings ??= new type.MCLSettings();
|
|
1204
|
+
const mclParams = this.settings?.mclSettings;
|
|
1205
|
+
|
|
1206
|
+
let counter = 0;
|
|
1207
|
+
const addedColCount = 4;
|
|
1208
|
+
const columnAddedSub = this.df.onColumnsAdded.subscribe((colArgs: DG.ColumnsArgs) => {
|
|
1209
|
+
for (const col of colArgs.columns) {
|
|
1210
|
+
if (col.name.toLowerCase().startsWith('embed') ||
|
|
1211
|
+
col.name.toLowerCase().startsWith('cluster')) {
|
|
1212
|
+
const gridCol = this.analysisView.grid.col(col.name);
|
|
1213
|
+
if (gridCol == null || this._mclCols.includes(col.name))
|
|
1214
|
+
continue;
|
|
1215
|
+
|
|
1216
|
+
gridCol.visible = false;
|
|
1217
|
+
this._mclCols.push(col.name);
|
|
1218
|
+
counter++;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
if (counter === addedColCount)
|
|
1222
|
+
columnAddedSub.unsubscribe();
|
|
1223
|
+
});
|
|
1224
|
+
const mclAdditionSub = grok.events.onViewerAdded.subscribe((info) => {
|
|
1225
|
+
try {
|
|
1226
|
+
const v = info.args.viewer as DG.ScatterPlotViewer;
|
|
1227
|
+
if (v.type === DG.VIEWER.SCATTER_PLOT) {
|
|
1228
|
+
if (this._sequenceSpaceViewer && this.analysisView.dockManager.findNode(this._sequenceSpaceViewer.root)) {
|
|
1229
|
+
const rootNode = this.analysisView.dockManager.findNode(this._sequenceSpaceViewer.root);
|
|
1230
|
+
setTimeout(() => {
|
|
1231
|
+
this.analysisView.dockManager.dock(v, DG.DOCK_TYPE.FILL, rootNode);
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
mclAdditionSub.unsubscribe();
|
|
1235
|
+
}
|
|
1236
|
+
} catch (e) {
|
|
1237
|
+
console.error(e);
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
const bioPreprocessingFunc = DG.Func.find({package: 'Bio', name: 'macromoleculePreprocessingFunction'})[0];
|
|
1242
|
+
const mclViewer = await markovCluster(
|
|
1243
|
+
this.df, [seqCol], [mclParams!.distanceF], [1],
|
|
1244
|
+
DistanceAggregationMethods.MANHATTAN, [bioPreprocessingFunc], [{
|
|
1245
|
+
gapOpen: mclParams!.gapOpen, gapExtend: mclParams!.gapExtend,
|
|
1246
|
+
fingerprintType: mclParams!.fingerprintType,
|
|
1247
|
+
}], mclParams!.threshold, mclParams!.maxIterations,
|
|
1248
|
+
);
|
|
1249
|
+
mclAdditionSub.unsubscribe();
|
|
1250
|
+
this._mclViewer = mclViewer ?? null;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1173
1253
|
/**
|
|
1174
1254
|
* Adds Sequence Space viewer to the analysis view
|
|
1175
1255
|
*/
|
|
@@ -1240,7 +1320,7 @@ export class PeptidesModel {
|
|
|
1240
1320
|
if (col.name.toLowerCase().startsWith('embed_') ||
|
|
1241
1321
|
( seqSpaceSettings.clusterEmbeddings && col.name.toLowerCase().startsWith('cluster'))) {
|
|
1242
1322
|
const gridCol = this.analysisView.grid.col(col.name);
|
|
1243
|
-
if (gridCol == null)
|
|
1323
|
+
if (gridCol == null || this._sequenceSpaceCols.includes(col.name))
|
|
1244
1324
|
continue;
|
|
1245
1325
|
|
|
1246
1326
|
gridCol.visible = false;
|
|
@@ -1252,8 +1332,25 @@ export class PeptidesModel {
|
|
|
1252
1332
|
columnAddedSub.unsubscribe();
|
|
1253
1333
|
});
|
|
1254
1334
|
|
|
1335
|
+
const seqSpaceAdditionSub = grok.events.onViewerAdded.subscribe((info) => {
|
|
1336
|
+
try {
|
|
1337
|
+
const v = info.args.viewer as DG.ScatterPlotViewer;
|
|
1338
|
+
if (v.type === DG.VIEWER.SCATTER_PLOT) {
|
|
1339
|
+
if (this._mclViewer && this.analysisView.dockManager.findNode(this._mclViewer.root)) {
|
|
1340
|
+
const rootNode = this.analysisView.dockManager.findNode(this._mclViewer.root);
|
|
1341
|
+
setTimeout(() => {
|
|
1342
|
+
this.analysisView.dockManager.dock(v, DG.DOCK_TYPE.FILL, rootNode);
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
seqSpaceAdditionSub.unsubscribe();
|
|
1346
|
+
}
|
|
1347
|
+
} catch (e) {
|
|
1348
|
+
console.error(e);
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1255
1351
|
const seqSpaceViewer: DG.ScatterPlotViewer | undefined =
|
|
1256
1352
|
await grok.functions.call('Bio:sequenceSpaceTopMenu', seqSpaceParams);
|
|
1353
|
+
seqSpaceAdditionSub.unsubscribe();
|
|
1257
1354
|
if (!(seqSpaceViewer instanceof DG.ScatterPlotViewer))
|
|
1258
1355
|
return;
|
|
1259
1356
|
|
package/src/package-test.ts
CHANGED
|
@@ -18,6 +18,10 @@ export {tests};
|
|
|
18
18
|
//input: object testContext {optional: true}
|
|
19
19
|
//output: dataframe result
|
|
20
20
|
export async function test(category: string, test: string, testContext: TestContext): Promise<DG.DataFrame> {
|
|
21
|
+
// const helmInit = DG.Func.find({name: 'initHelm'})[0];
|
|
22
|
+
// if (helmInit)
|
|
23
|
+
// await helmInit.apply();
|
|
24
|
+
testContext.catchUnhandled = false;
|
|
21
25
|
const data = await runTests({category, test, testContext});
|
|
22
26
|
return DG.DataFrame.fromObjects(data)!;
|
|
23
27
|
}
|
package/src/tests/core.ts
CHANGED
|
@@ -12,29 +12,19 @@ import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-librarie
|
|
|
12
12
|
import {MonomerPosition} from '../viewers/sar-viewer';
|
|
13
13
|
|
|
14
14
|
category('Core', () => {
|
|
15
|
-
let simpleTable: DG.DataFrame;
|
|
16
|
-
let simpleActivityCol: DG.Column<number>;
|
|
17
|
-
let simpleAlignedSeqCol: DG.Column<string>;
|
|
18
|
-
let simpleScaledCol: DG.Column<number>;
|
|
19
|
-
|
|
20
|
-
let complexTable: DG.DataFrame;
|
|
21
|
-
let complexActivityCol: DG.Column<number>;
|
|
22
|
-
let complexAlignedSeqCol: DG.Column<string>;
|
|
23
|
-
let complexScaledCol: DG.Column<number>;
|
|
24
15
|
const alignedSequenceCol = 'AlignedSequence';
|
|
25
16
|
|
|
26
17
|
let model: PeptidesModel | null = null;
|
|
27
|
-
|
|
28
18
|
test('Start analysis: simple', async () => {
|
|
29
19
|
const simpleActivityColName = 'IC50';
|
|
30
|
-
simpleTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned.csv'));
|
|
31
|
-
simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
32
|
-
simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
20
|
+
const simpleTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned.csv'));
|
|
21
|
+
const simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
22
|
+
const simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
33
23
|
simpleAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
34
24
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
35
25
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
36
26
|
simpleAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
37
|
-
simpleScaledCol = scaleActivity(simpleActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
27
|
+
const simpleScaledCol = scaleActivity(simpleActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
38
28
|
|
|
39
29
|
model = await startAnalysis(
|
|
40
30
|
simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, C.SCALING_METHODS.MINUS_LG);
|
|
@@ -47,15 +37,15 @@ category('Core', () => {
|
|
|
47
37
|
|
|
48
38
|
test('Start analysis: сomplex', async () => {
|
|
49
39
|
const complexActivityColName = 'Activity';
|
|
50
|
-
complexTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned_2.csv'));
|
|
51
|
-
complexActivityCol = complexTable.getCol(complexActivityColName);
|
|
52
|
-
complexAlignedSeqCol = complexTable.getCol('MSA');
|
|
40
|
+
const complexTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned_2.csv'));
|
|
41
|
+
const complexActivityCol = complexTable.getCol(complexActivityColName);
|
|
42
|
+
const complexAlignedSeqCol = complexTable.getCol('MSA');
|
|
53
43
|
complexAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
54
44
|
complexAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.UN);
|
|
55
45
|
complexAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
56
46
|
complexAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
57
47
|
complexAlignedSeqCol.setTag(C.TAGS.SEPARATOR, '/');
|
|
58
|
-
complexScaledCol = scaleActivity(complexActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
48
|
+
const complexScaledCol = scaleActivity(complexActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
59
49
|
|
|
60
50
|
model = await startAnalysis(
|
|
61
51
|
complexActivityCol, complexAlignedSeqCol, null, complexTable, complexScaledCol, C.SCALING_METHODS.MINUS_LG);
|
|
@@ -68,14 +58,14 @@ category('Core', () => {
|
|
|
68
58
|
|
|
69
59
|
test('Save and load project', async () => {
|
|
70
60
|
const simpleActivityColName = 'IC50';
|
|
71
|
-
simpleTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned.csv'));
|
|
72
|
-
simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
73
|
-
simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
61
|
+
const simpleTable = DG.DataFrame.fromCsv(await _package.files.readAsText('aligned.csv'));
|
|
62
|
+
const simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
63
|
+
const simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
74
64
|
simpleAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
75
65
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
76
66
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
77
67
|
simpleAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
78
|
-
simpleScaledCol = scaleActivity(simpleActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
68
|
+
const simpleScaledCol = scaleActivity(simpleActivityCol, C.SCALING_METHODS.MINUS_LG);
|
|
79
69
|
|
|
80
70
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol,
|
|
81
71
|
C.SCALING_METHODS.MINUS_LG);
|
|
@@ -106,4 +96,4 @@ category('Core', () => {
|
|
|
106
96
|
await grok.dapi.tables.delete(sti);
|
|
107
97
|
await grok.dapi.projects.delete(sp);
|
|
108
98
|
}, {skipReason: 'ViewLayout should become ViewInfo in 1.18.'});
|
|
109
|
-
});
|
|
99
|
+
}, {clear: true});
|
package/src/tests/viewers.ts
CHANGED
|
@@ -24,7 +24,8 @@ category('Viewers: Basic', () => {
|
|
|
24
24
|
const viewers = DG.Func.find({package: 'Peptides', tags: ['viewer']}).map((f) => f.friendlyName);
|
|
25
25
|
for (const v of viewers) {
|
|
26
26
|
test(v, async () => {
|
|
27
|
-
await testViewer(v, df.clone(), {detectSemanticTypes: true, arbitraryDfTest: false});
|
|
27
|
+
await testViewer(v, df.clone(), {detectSemanticTypes: true, arbitraryDfTest: false, readOnly: true});
|
|
28
|
+
await delay(1000);
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
});
|
package/src/tests/widgets.ts
CHANGED
|
@@ -48,7 +48,7 @@ category('Widgets: Settings', () => {
|
|
|
48
48
|
|
|
49
49
|
// Check number of panes
|
|
50
50
|
const panes = settingsElements.accordion.panes.map((pane) => pane.name);
|
|
51
|
-
expect(panes.length,
|
|
51
|
+
expect(panes.length, 5, `Expected 5 panes, got ${settingsElements.accordion.panes.length}`);
|
|
52
52
|
for (const paneName of Object.values(SETTINGS_PANES))
|
|
53
53
|
expect(panes.includes(paneName), true, `Pane ${paneName} is missing`);
|
|
54
54
|
|
|
@@ -153,6 +153,7 @@ category('Widgets: Actions', () => {
|
|
|
153
153
|
|
|
154
154
|
before(async () => {
|
|
155
155
|
df = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/HELM_small.csv'));
|
|
156
|
+
await df.meta.detectSemanticTypes();
|
|
156
157
|
activityCol = df.getCol(TEST_COLUMN_NAMES.ACTIVITY);
|
|
157
158
|
sequenceCol = df.getCol(TEST_COLUMN_NAMES.SEQUENCE);
|
|
158
159
|
sequenceCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
@@ -179,13 +180,14 @@ category('Widgets: Actions', () => {
|
|
|
179
180
|
|
|
180
181
|
const selection = model.df.selection;
|
|
181
182
|
selection.set(0, true, false);
|
|
183
|
+
selection.set(1, true, false);
|
|
182
184
|
|
|
183
185
|
const newViewId = model.createNewView();
|
|
184
186
|
const currentTable = grok.shell.t;
|
|
185
187
|
|
|
186
188
|
expect(currentTable.getTag(C.TAGS.MULTIPLE_VIEWS), '1', 'Current table is expected to have multiple views tag');
|
|
187
189
|
expect(currentTable.getTag(DG.TAGS.ID), newViewId, 'Current table is expected to have the same UUID as new view');
|
|
188
|
-
expect(currentTable.rowCount,
|
|
190
|
+
expect(currentTable.rowCount, 2, 'Current table is expected to have 2 rows');
|
|
189
191
|
|
|
190
192
|
await delay(500);
|
|
191
193
|
const currentTableModel = currentTable.temp[PeptidesModel.modelName] as PeptidesModel;
|
|
@@ -59,7 +59,7 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
|
|
|
59
59
|
|
|
60
60
|
const x = currentMeanDifference >= 0 ? pValComplement : -pValComplement;
|
|
61
61
|
const coef = DG.Color.toHtml(pVal === null ? DG.Color.lightLightGray :
|
|
62
|
-
DG.Color.scaleColor(x, -centeredPValLimit, centeredPValLimit));
|
|
62
|
+
DG.Color.scaleColor(x, -centeredPValLimit, centeredPValLimit, 255));
|
|
63
63
|
|
|
64
64
|
const halfWidth = bounds.width / 2;
|
|
65
65
|
const maxMeanDifference = Math.max(Math.abs(viewer.monomerPositionStats.general.minMeanDifference),
|
|
@@ -110,13 +110,17 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
|
|
|
110
110
|
* @param bounds - Cell bounds.
|
|
111
111
|
* @param color - Cell color.
|
|
112
112
|
*/
|
|
113
|
+
|
|
114
|
+
function setAlpha(color: number, alpha: number): number {
|
|
115
|
+
return (color & 0x00ffffff | (alpha << 24)) >>> 0;
|
|
116
|
+
}
|
|
113
117
|
export function renderInvariantMapCell(canvasContext: CanvasRenderingContext2D, currentMonomer: string,
|
|
114
118
|
currentPosition: string, invariantMapSelection: type.Selection, cellValue: number, bounds: DG.Rect,
|
|
115
119
|
color: number): void {
|
|
116
120
|
//FIXME: This is a hack, because `color` value sometimes comes incomplete. E.g. we found that here `color` value is
|
|
117
121
|
// 255 and its contrast color would be black, which is not visible on blue (color code) background. The full number
|
|
118
122
|
// is actually 4278190335.
|
|
119
|
-
color = DG.Color.fromHtml(DG.Color.toHtml(color));
|
|
123
|
+
color = DG.Color.fromHtml(DG.Color.toHtml(setAlpha(color, 255)));
|
|
120
124
|
canvasContext.fillStyle = DG.Color.toHtml(color);
|
|
121
125
|
canvasContext.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
122
126
|
canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
|
package/src/utils/misc.ts
CHANGED
|
@@ -271,6 +271,7 @@ export function modifySelection(selection: type.Selection, clusterOrMonomerPosit
|
|
|
271
271
|
*/
|
|
272
272
|
export function highlightMonomerPosition(monomerPosition: type.SelectionItem, dataFrame: DG.DataFrame,
|
|
273
273
|
monomerPositionStats: MonomerPositionStats): void {
|
|
274
|
+
if (!dataFrame) return;
|
|
274
275
|
const bitArray = new BitArray(dataFrame.rowCount);
|
|
275
276
|
if (monomerPosition.positionOrClusterType === C.COLUMNS_NAMES.MONOMER) {
|
|
276
277
|
const positionStats = Object.values(monomerPositionStats);
|
|
@@ -387,3 +388,14 @@ export function isApplicableDataframe(table: DG.DataFrame, minRows: number = 2):
|
|
|
387
388
|
return table.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE).length > 0 &&
|
|
388
389
|
wu(table.columns.numerical).toArray().length > 0 && table.rowCount >= minRows;
|
|
389
390
|
}
|
|
391
|
+
|
|
392
|
+
export function debounce<T extends Array<any>, K>(f: (...args: T) => Promise<K>, timeout: number = 500,
|
|
393
|
+
): (...args: T) => Promise<K> {
|
|
394
|
+
let timer: NodeJS.Timeout | number | undefined;
|
|
395
|
+
return async (...args: T) => {
|
|
396
|
+
return new Promise<K>((resolve) => {
|
|
397
|
+
clearTimeout(timer);
|
|
398
|
+
timer = setTimeout(() => resolve(f(...args)), timeout);
|
|
399
|
+
});
|
|
400
|
+
};
|
|
401
|
+
}
|
package/src/utils/types.ts
CHANGED
|
@@ -20,8 +20,19 @@ export interface PeptidesSettings {
|
|
|
20
20
|
showMostPotentResidues?: boolean,
|
|
21
21
|
showLogoSummaryTable?: boolean,
|
|
22
22
|
showDendrogram?: boolean,
|
|
23
|
+
showSequenceSpace?: boolean,
|
|
23
24
|
columns?: AggregationColumns,
|
|
24
25
|
sequenceSpaceParams: SequenceSpaceParams,
|
|
26
|
+
mclSettings: MCLSettings,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class MCLSettings {
|
|
30
|
+
maxIterations: number = 5;
|
|
31
|
+
threshold: number = 80;
|
|
32
|
+
distanceF: MmDistanceFunctionsNames = MmDistanceFunctionsNames.NEEDLEMANN_WUNSCH;
|
|
33
|
+
gapOpen: number = 1;
|
|
34
|
+
gapExtend: number = 0.6;
|
|
35
|
+
fingerprintType: string = 'Morgan';
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
export class SequenceSpaceParams {
|
|
@@ -23,6 +23,7 @@ import {_package} from '../package';
|
|
|
23
23
|
import {showTooltip} from '../utils/tooltips';
|
|
24
24
|
import {calculateMonomerPositionStatistics, findMutations, MutationCliffsOptions} from '../utils/algorithms';
|
|
25
25
|
import {
|
|
26
|
+
debounce,
|
|
26
27
|
extractColInfo,
|
|
27
28
|
getTotalAggColumns,
|
|
28
29
|
highlightMonomerPosition,
|
|
@@ -91,6 +92,9 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
91
92
|
maxMutations: number;
|
|
92
93
|
_scaledActivityColumn: DG.Column | null = null;
|
|
93
94
|
doRender: boolean = true;
|
|
95
|
+
mutationCliffsDebouncer: (
|
|
96
|
+
activityArray: type.RawData, monomerInfoArray: type.RawColumn[], options?: MutationCliffsOptions
|
|
97
|
+
) => Promise<type.MutationCliffs>;
|
|
94
98
|
|
|
95
99
|
/** Sets common properties for inheritor viewers. */
|
|
96
100
|
protected constructor() {
|
|
@@ -111,11 +115,16 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
111
115
|
this.minActivityDelta = this.float(SAR_PROPERTIES.MIN_ACTIVITY_DELTA, 0,
|
|
112
116
|
{category: PROPERTY_CATEGORIES.MUTATION_CLIFFS, min: 0, max: 100});
|
|
113
117
|
this.maxMutations = this.int(SAR_PROPERTIES.MAX_MUTATIONS, 1,
|
|
114
|
-
{category: PROPERTY_CATEGORIES.MUTATION_CLIFFS, min: 1, max:
|
|
118
|
+
{category: PROPERTY_CATEGORIES.MUTATION_CLIFFS, min: 1, max: 20});
|
|
115
119
|
|
|
116
120
|
this.columns = this.columnList(SAR_PROPERTIES.COLUMNS, [], {category: PROPERTY_CATEGORIES.AGGREGATION});
|
|
117
121
|
this.aggregation = this.string(SAR_PROPERTIES.AGGREGATION, DG.AGG.AVG,
|
|
118
122
|
{category: PROPERTY_CATEGORIES.AGGREGATION, choices: C.AGGREGATION_TYPES});
|
|
123
|
+
|
|
124
|
+
this.mutationCliffsDebouncer = debounce(
|
|
125
|
+
async (activityArray: type.RawData, monomerInfoArray: type.RawColumn[], options?: MutationCliffsOptions) => {
|
|
126
|
+
return await findMutations(activityArray, monomerInfoArray, options);
|
|
127
|
+
});
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
_viewerGrid: DG.Grid | null = null;
|
|
@@ -433,7 +442,7 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
433
442
|
* @return - mutation cliffs.
|
|
434
443
|
*/
|
|
435
444
|
async calculateMutationCliffs(): Promise<MutationCliffs> {
|
|
436
|
-
const scaledActivityCol: DG.Column<number> = this.dataFrame.getCol(this.
|
|
445
|
+
const scaledActivityCol: DG.Column<number> = this.dataFrame.getCol(this.activityColumnName);
|
|
437
446
|
//TODO: set categories ordering the same to share compare indexes instead of strings
|
|
438
447
|
const monomerCols: type.RawColumn[] = this.positionColumns.map(extractColInfo);
|
|
439
448
|
const targetCol = this.targetColumnName ? extractColInfo(this.dataFrame.getCol(this.targetColumnName)) : null;
|
|
@@ -442,7 +451,7 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
442
451
|
maxMutations: this.maxMutations, minActivityDelta: this.minActivityDelta,
|
|
443
452
|
targetCol, currentTarget: this.targetCategory,
|
|
444
453
|
};
|
|
445
|
-
return await
|
|
454
|
+
return await this.mutationCliffsDebouncer(scaledActivityCol.getRawData(), monomerCols, options);
|
|
446
455
|
}
|
|
447
456
|
}
|
|
448
457
|
|
package/src/widgets/peptides.ts
CHANGED
|
@@ -130,7 +130,7 @@ export function analyzePeptidesUI(df: DG.DataFrame, col?: DG.Column<string>): Di
|
|
|
130
130
|
bitsetChanged.unsubscribe();
|
|
131
131
|
if (sequencesCol) {
|
|
132
132
|
const model = await startAnalysis(activityColumnChoice.value!, sequencesCol, clustersColumnChoice.value, df,
|
|
133
|
-
scaledCol, activityScalingMethod.value ?? C.SCALING_METHODS.NONE, {addSequenceSpace: true,
|
|
133
|
+
scaledCol, activityScalingMethod.value ?? C.SCALING_METHODS.NONE, {addSequenceSpace: false, addMCL: true,
|
|
134
134
|
useEmbeddingsClusters: generateClustersInput.value ?? false});
|
|
135
135
|
return model !== null;
|
|
136
136
|
}
|
|
@@ -167,6 +167,7 @@ export function analyzePeptidesUI(df: DG.DataFrame, col?: DG.Column<string>): Di
|
|
|
167
167
|
type AnalysisOptions = {
|
|
168
168
|
addSequenceSpace?: boolean,
|
|
169
169
|
useEmbeddingsClusters?: boolean,
|
|
170
|
+
addMCL?: boolean,
|
|
170
171
|
};
|
|
171
172
|
|
|
172
173
|
/**
|
|
@@ -207,8 +208,9 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
|
|
|
207
208
|
|
|
208
209
|
const settings: type.PeptidesSettings = {
|
|
209
210
|
sequenceColumnName: peptidesCol.name, activityColumnName: activityColumn.name, activityScaling: scaling,
|
|
210
|
-
columns: {}, showDendrogram: false,
|
|
211
|
+
columns: {}, showDendrogram: false, showSequenceSpace: false,
|
|
211
212
|
sequenceSpaceParams: new type.SequenceSpaceParams(!!options.useEmbeddingsClusters && !clustersColumn),
|
|
213
|
+
mclSettings: new type.MCLSettings(),
|
|
212
214
|
};
|
|
213
215
|
|
|
214
216
|
if (clustersColumn) {
|
|
@@ -253,6 +255,25 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
|
|
|
253
255
|
}, 100);
|
|
254
256
|
}
|
|
255
257
|
}
|
|
258
|
+
} else if (options.addMCL ?? false) {
|
|
259
|
+
await model.addMCLClusters();
|
|
260
|
+
if (!clustersColumn && (options.useEmbeddingsClusters ?? false)) {
|
|
261
|
+
const mclClusterCol = model._mclCols
|
|
262
|
+
.find(
|
|
263
|
+
(col) => model?.df.col(col) && col.toLowerCase().startsWith('cluster') && !col.toLowerCase().includes('size'),
|
|
264
|
+
);
|
|
265
|
+
if (mclClusterCol) {
|
|
266
|
+
const lstProps: ILogoSummaryTable = {
|
|
267
|
+
clustersColumnName: mclClusterCol, sequenceColumnName: peptidesCol.name, activityScaling: scaling,
|
|
268
|
+
activityColumnName: activityColumn.name,
|
|
269
|
+
};
|
|
270
|
+
await model.addLogoSummaryTable(lstProps);
|
|
271
|
+
setTimeout(() => {
|
|
272
|
+
model && (model?.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable)?.render &&
|
|
273
|
+
(model?.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable)?.render();
|
|
274
|
+
}, 100);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
256
277
|
}
|
|
257
278
|
|
|
258
279
|
|
package/src/widgets/settings.ts
CHANGED
|
@@ -19,6 +19,7 @@ export enum SETTINGS_PANES {
|
|
|
19
19
|
VIEWERS = 'Viewers',
|
|
20
20
|
COLUMNS = 'Columns',
|
|
21
21
|
SEQUENCE_SPACE = 'Sequence space',
|
|
22
|
+
MCL = 'MCL',
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export enum GENERAL_INPUTS {
|
|
@@ -44,12 +45,22 @@ export enum SEQUENCE_SPACE_INPUTS {
|
|
|
44
45
|
FINGERPRINT_TYPE = 'Fingerprint type',
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
export enum MCL_INPUTS {
|
|
49
|
+
DISTANCE_FUNCTION = 'Distance function',
|
|
50
|
+
GAP_OPEN = 'Gap open penalty',
|
|
51
|
+
GAP_EXTEND = 'Gap extend penalty',
|
|
52
|
+
FINGERPRINT_TYPE = 'Fingerprint type',
|
|
53
|
+
THRESHOLD = 'Similarity threshold',
|
|
54
|
+
MAX_ITERATIONS = 'Max iterations',
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
|
|
48
58
|
export const PANES_INPUTS = {
|
|
49
59
|
[SETTINGS_PANES.GENERAL]: GENERAL_INPUTS,
|
|
50
60
|
[SETTINGS_PANES.VIEWERS]: VIEWERS_INPUTS,
|
|
51
61
|
[SETTINGS_PANES.COLUMNS]: COLUMNS_INPUTS,
|
|
52
62
|
[SETTINGS_PANES.SEQUENCE_SPACE]: SEQUENCE_SPACE_INPUTS,
|
|
63
|
+
[SETTINGS_PANES.MCL]: MCL_INPUTS,
|
|
53
64
|
};
|
|
54
65
|
|
|
55
66
|
/**
|
|
@@ -69,7 +80,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
69
80
|
const result: type.PartialPeptidesSettings = {};
|
|
70
81
|
const inputs: PaneInputs = {};
|
|
71
82
|
const seqSpaceParams = settings?.sequenceSpaceParams ?? new type.SequenceSpaceParams();
|
|
72
|
-
|
|
83
|
+
const mclParams = settings?.mclSettings ?? new type.MCLSettings();
|
|
73
84
|
// General pane options
|
|
74
85
|
const activityCol = ui.columnInput(GENERAL_INPUTS.ACTIVITY, model.df,
|
|
75
86
|
model.df.getCol(model.settings!.activityColumnName!), () => result.activityColumnName = activityCol.value!.name,
|
|
@@ -102,10 +113,23 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
102
113
|
const isDendrogramEnabled = wu(model.analysisView.viewers).some((v) => v.type === VIEWER_TYPE.DENDROGRAM);
|
|
103
114
|
const dendrogram = ui.boolInput(VIEWER_TYPE.DENDROGRAM, isDendrogramEnabled ?? false,
|
|
104
115
|
() => result.showDendrogram = dendrogram.value) as DG.InputBase<boolean>;
|
|
116
|
+
const showSeqSpace = ui.boolInput('Sequence space', !!settings?.showSequenceSpace, () => {
|
|
117
|
+
result.showSequenceSpace = showSeqSpace.value ?? undefined;
|
|
118
|
+
if (showSeqSpace.value) {
|
|
119
|
+
seqSpacePane.root.style.display = 'flex';
|
|
120
|
+
if (!settings?.showSequenceSpace)
|
|
121
|
+
result.sequenceSpaceParams = seqSpaceParams;
|
|
122
|
+
} else {
|
|
123
|
+
seqSpacePane.root.style.display = 'none';
|
|
124
|
+
delete result.sequenceSpaceParams;
|
|
125
|
+
}
|
|
126
|
+
if (result.showSequenceSpace === settings?.showSequenceSpace)
|
|
127
|
+
delete result.showSequenceSpace;
|
|
128
|
+
});
|
|
105
129
|
dendrogram.setTooltip('Show dendrogram viewer');
|
|
106
130
|
dendrogram.enabled = getTreeHelperInstance() !== null;
|
|
107
131
|
|
|
108
|
-
accordion.addPane(SETTINGS_PANES.VIEWERS, () => ui.inputs([dendrogram]), true);
|
|
132
|
+
accordion.addPane(SETTINGS_PANES.VIEWERS, () => ui.inputs([dendrogram, showSeqSpace]), true);
|
|
109
133
|
inputs[SETTINGS_PANES.VIEWERS] = [dendrogram];
|
|
110
134
|
|
|
111
135
|
// Columns to include pane options
|
|
@@ -182,7 +206,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
182
206
|
input.root.style.display = 'none';
|
|
183
207
|
});
|
|
184
208
|
}
|
|
185
|
-
|
|
209
|
+
// SEQ SPACE INPUTS
|
|
186
210
|
const distanceFunctionInput = ui.choiceInput(SEQUENCE_SPACE_INPUTS.DISTANCE_FUNCTION, seqSpaceParams.distanceF,
|
|
187
211
|
[distFNames.NEEDLEMANN_WUNSCH, distFNames.HAMMING, distFNames.LEVENSHTEIN, distFNames.MONOMER_CHEMICAL_DISTANCE],
|
|
188
212
|
() => onSeqSpaceParamsChange('distanceF', distanceFunctionInput.value));
|
|
@@ -203,7 +227,8 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
203
227
|
() => onSeqSpaceParamsChange('minPts', minPtsInput.value));
|
|
204
228
|
minPtsInput.setTooltip('Minimum number of points in a cluster');
|
|
205
229
|
const fingerprintTypesInput = ui.choiceInput('Fingerprint type', seqSpaceParams.fingerprintType,
|
|
206
|
-
['Morgan', 'RDKit', 'Pattern'
|
|
230
|
+
['Morgan', 'RDKit', 'Pattern', 'AtomPair', 'MACCS', 'TopologicalTorsion'],
|
|
231
|
+
() => onSeqSpaceParamsChange('fingerprintType', fingerprintTypesInput.value));
|
|
207
232
|
function correctSeqSpaceInputs(): void {
|
|
208
233
|
toggleInputs([gapOpenInput, gapExtendInput], distanceFunctionInput.value === distFNames.NEEDLEMANN_WUNSCH);
|
|
209
234
|
toggleInputs([epsilonInput, minPtsInput], clusterEmbeddingsInput.value === true);
|
|
@@ -212,14 +237,70 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
212
237
|
distanceFunctionInput.value === distFNames.NEEDLEMANN_WUNSCH);
|
|
213
238
|
}
|
|
214
239
|
correctSeqSpaceInputs();
|
|
240
|
+
// END OF SEQ SPACE INPUTS
|
|
241
|
+
|
|
242
|
+
//MCL INPUTS
|
|
243
|
+
|
|
244
|
+
const modifiedMCLParams: Partial<type.MCLSettings> = {};
|
|
245
|
+
function onMCLParamsChange(fieldName: keyof type.MCLSettings, value: any): void {
|
|
246
|
+
correctMCLInputs();
|
|
247
|
+
//correctSeqSpaceInputs();
|
|
248
|
+
if (value === null || value === undefined || value === '')
|
|
249
|
+
return;
|
|
250
|
+
modifiedMCLParams[fieldName] = value;
|
|
251
|
+
let isAllSame = true;
|
|
252
|
+
for (const [key, val] of Object.entries(modifiedMCLParams)) {
|
|
253
|
+
if (val !== mclParams[key as keyof type.MCLSettings]) {
|
|
254
|
+
isAllSame = false;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (isAllSame)
|
|
259
|
+
delete result.mclSettings;
|
|
260
|
+
else
|
|
261
|
+
result.mclSettings = {...mclParams, ...modifiedMCLParams};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function correctMCLInputs(): void {
|
|
265
|
+
toggleInputs([mclGapOpenInput, mclGapExtendInput], mclDistanceFunctionInput.value === distFNames.NEEDLEMANN_WUNSCH);
|
|
266
|
+
toggleInputs([mclFingerprintTypesInput],
|
|
267
|
+
mclDistanceFunctionInput.value === distFNames.MONOMER_CHEMICAL_DISTANCE ||
|
|
268
|
+
mclDistanceFunctionInput.value === distFNames.NEEDLEMANN_WUNSCH);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const mclDistanceFunctionInput = ui.choiceInput(SEQUENCE_SPACE_INPUTS.DISTANCE_FUNCTION, mclParams.distanceF,
|
|
272
|
+
[distFNames.NEEDLEMANN_WUNSCH, distFNames.MONOMER_CHEMICAL_DISTANCE, distFNames.HAMMING, distFNames.LEVENSHTEIN],
|
|
273
|
+
() => onMCLParamsChange('distanceF', mclDistanceFunctionInput.value));
|
|
274
|
+
const mclGapOpenInput = ui.floatInput(SEQUENCE_SPACE_INPUTS.GAP_OPEN, mclParams.gapOpen,
|
|
275
|
+
() => onMCLParamsChange('gapOpen', mclGapOpenInput.value));
|
|
276
|
+
const mclGapExtendInput = ui.floatInput(SEQUENCE_SPACE_INPUTS.GAP_EXTEND, mclParams.gapExtend,
|
|
277
|
+
() => onMCLParamsChange('gapExtend', mclGapExtendInput.value));
|
|
278
|
+
const mclFingerprintTypesInput = ui.choiceInput('Fingerprint type', mclParams.fingerprintType,
|
|
279
|
+
['Morgan', 'RDKit', 'Pattern', 'AtomPair', 'MACCS', 'TopologicalTorsion'],
|
|
280
|
+
() => onMCLParamsChange('fingerprintType', mclFingerprintTypesInput.value));
|
|
281
|
+
const mclThresholdInput = ui.intInput('Similarity threshold', mclParams.threshold ?? 80,
|
|
282
|
+
() => onMCLParamsChange('threshold', mclThresholdInput.value));
|
|
283
|
+
const mclMaxIterationsInput = ui.intInput('Max iterations', mclParams.maxIterations ?? 5,
|
|
284
|
+
() => onMCLParamsChange('maxIterations', mclMaxIterationsInput.value));
|
|
285
|
+
correctMCLInputs();
|
|
286
|
+
|
|
287
|
+
const mclInputs = [mclThresholdInput, mclDistanceFunctionInput, mclFingerprintTypesInput,
|
|
288
|
+
mclGapOpenInput, mclGapExtendInput, mclMaxIterationsInput];
|
|
289
|
+
|
|
290
|
+
accordion.addPane(SETTINGS_PANES.MCL, () => ui.inputs(mclInputs), true);
|
|
291
|
+
inputs[SETTINGS_PANES.MCL] = mclInputs;
|
|
292
|
+
// END OF MCL INPUTS
|
|
215
293
|
|
|
216
294
|
const seqSpaceInputs = [distanceFunctionInput, fingerprintTypesInput, gapOpenInput,
|
|
217
295
|
gapExtendInput, clusterEmbeddingsInput, epsilonInput, minPtsInput];
|
|
218
|
-
accordion.addPane(SETTINGS_PANES.SEQUENCE_SPACE, () => ui.inputs(seqSpaceInputs), true);
|
|
296
|
+
const seqSpacePane = accordion.addPane(SETTINGS_PANES.SEQUENCE_SPACE, () => ui.inputs(seqSpaceInputs), true);
|
|
219
297
|
inputs[SETTINGS_PANES.SEQUENCE_SPACE] = seqSpaceInputs;
|
|
298
|
+
showSeqSpace.fireChanged();
|
|
220
299
|
const dialog = ui.dialog('Peptides settings').add(accordion);
|
|
221
300
|
dialog.root.style.width = '400px';
|
|
222
|
-
dialog.onOK(() =>
|
|
301
|
+
dialog.onOK(() => {
|
|
302
|
+
model.settings = result;
|
|
303
|
+
});
|
|
223
304
|
dialog.show();
|
|
224
305
|
|
|
225
306
|
return {dialog, accordion, inputs};
|