@datagrok/peptides 1.4.0 → 1.7.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/.eslintrc.json +2 -0
- package/dist/package-test.js +6093 -60759
- package/dist/package.js +5726 -60613
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +356 -267
- package/files/tests/aligned_5k.d42 +0 -0
- package/package.json +15 -22
- package/src/model.ts +644 -554
- package/src/package-test.ts +2 -0
- package/src/package.ts +35 -61
- package/src/styles.css +7 -0
- package/src/tests/algorithms.ts +29 -20
- package/src/tests/core.ts +57 -19
- package/src/tests/peptide-space-test.ts +5 -53
- package/src/tests/utils.ts +4 -4
- package/src/tests/viewers.ts +17 -0
- package/src/utils/algorithms.ts +25 -22
- package/src/utils/cell-renderer.ts +48 -43
- package/src/utils/constants.ts +14 -37
- package/src/utils/misc.ts +29 -18
- package/src/utils/peptide-similarity-space.ts +5 -8
- package/src/utils/statistics.ts +18 -9
- package/src/utils/types.ts +8 -0
- package/src/viewers/logo-summary.ts +287 -53
- package/src/viewers/peptide-space-viewer.ts +5 -5
- package/src/viewers/sar-viewer.ts +245 -58
- package/src/widgets/distribution.ts +102 -32
- package/src/widgets/manual-alignment.ts +3 -3
- package/src/widgets/mutation-cliffs.ts +8 -5
- package/src/widgets/peptides.ts +78 -40
- package/src/widgets/settings.ts +20 -16
- package/tsconfig.json +3 -3
- package/jest.config.js +0 -33
- package/src/__jest__/remote.test.ts +0 -69
- package/src/__jest__/test-node.ts +0 -97
- package/test-Peptides-62cc009524f3-d4fc804f.html +0 -276
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
3
|
import * as DG from 'datagrok-api/dg';
|
|
3
4
|
|
|
4
5
|
import $ from 'cash-dom';
|
|
5
6
|
import {PeptidesModel} from '../model';
|
|
6
7
|
import * as C from '../utils/constants';
|
|
7
8
|
import * as CR from '../utils/cell-renderer';
|
|
8
|
-
import
|
|
9
|
+
import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
|
+
import {PositionHeight} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
11
|
+
import {getStats, MaskInfo, Stats} from '../utils/statistics';
|
|
12
|
+
import wu from 'wu';
|
|
13
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
9
14
|
|
|
10
15
|
export class LogoSummary extends DG.JsViewer {
|
|
11
16
|
_titleHost = ui.divText('Logo Summary Table', {id: 'pep-viewer-title'});
|
|
@@ -13,29 +18,35 @@ export class LogoSummary extends DG.JsViewer {
|
|
|
13
18
|
viewerGrid!: DG.Grid;
|
|
14
19
|
initialized: boolean = false;
|
|
15
20
|
webLogoMode: string;
|
|
16
|
-
|
|
21
|
+
membersRatioThreshold: number;
|
|
22
|
+
newClusterName: string;
|
|
23
|
+
webLogoDfPlot: DG.DataFramePlotHelper[] = [];
|
|
24
|
+
distributionDfPlot: DG.DataFramePlotHelper[] = [];
|
|
17
25
|
|
|
18
26
|
constructor() {
|
|
19
27
|
super();
|
|
20
28
|
|
|
21
|
-
this.webLogoMode = this.string('webLogoMode',
|
|
22
|
-
|
|
29
|
+
this.webLogoMode = this.string('webLogoMode', PositionHeight.full,
|
|
30
|
+
{choices: [PositionHeight.full, PositionHeight.Entropy]});
|
|
31
|
+
this.membersRatioThreshold = this.float('membersRatioThreshold', 0.7, {min: 0, max: 1.0});
|
|
32
|
+
this.newClusterName = this.string('newClusterName', 'New cluster');
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
onTableAttached(): void {
|
|
26
36
|
super.onTableAttached();
|
|
27
37
|
|
|
28
|
-
this.model =
|
|
38
|
+
this.model = PeptidesModel.getInstance(this.dataFrame);
|
|
29
39
|
this.subs.push(this.model.onSettingsChanged.subscribe(() => {
|
|
30
40
|
this.createLogoSummaryGrid();
|
|
31
41
|
this.render();
|
|
32
42
|
}));
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
this.subs.push(this.model.onNewCluster.subscribe(() => this.clusterFromSelection()));
|
|
44
|
+
this.subs.push(this.model.onRemoveCluster.subscribe(() => this.removeCluster()));
|
|
45
|
+
this.subs.push(this.model.onFilterChanged.subscribe(() => {
|
|
46
|
+
this.createLogoSummaryGrid();
|
|
47
|
+
this.render();
|
|
48
|
+
}));
|
|
49
|
+
|
|
39
50
|
this.createLogoSummaryGrid();
|
|
40
51
|
this.initialized = true;
|
|
41
52
|
this.render();
|
|
@@ -46,83 +57,213 @@ export class LogoSummary extends DG.JsViewer {
|
|
|
46
57
|
render(): void {
|
|
47
58
|
if (this.initialized) {
|
|
48
59
|
$(this.root).empty();
|
|
60
|
+
const df = this.viewerGrid.dataFrame;
|
|
61
|
+
if (!df.filter.anyTrue) {
|
|
62
|
+
const emptyDf = ui.divText('No clusters to satisfy the threshold. ' +
|
|
63
|
+
'Please, lower the threshold in viewer proeperties to include clusters');
|
|
64
|
+
this.root.appendChild(ui.divV([this._titleHost, emptyDf]));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
49
67
|
this.viewerGrid.root.style.width = 'auto';
|
|
50
68
|
this.root.appendChild(ui.divV([this._titleHost, this.viewerGrid.root]));
|
|
51
69
|
this.viewerGrid.invalidate();
|
|
52
70
|
}
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
onPropertyChanged(): void {
|
|
56
|
-
|
|
73
|
+
onPropertyChanged(property: DG.Property): void {
|
|
74
|
+
super.onPropertyChanged(property);
|
|
75
|
+
if (property.name == 'membersRatioThreshold')
|
|
76
|
+
this.updateFilter();
|
|
57
77
|
this.render();
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
createLogoSummaryGrid(): DG.Grid {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
const clustersColName = this.model.settings.clustersColumnName!;
|
|
82
|
+
const isDfFiltered = this.dataFrame.filter.anyFalse;
|
|
83
|
+
const filteredDf = isDfFiltered ? this.dataFrame.clone(this.dataFrame.filter) : this.dataFrame;
|
|
84
|
+
const filteredDfCols = filteredDf.columns;
|
|
85
|
+
const activityCol = filteredDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
86
|
+
const activityColData = activityCol.getRawData();
|
|
87
|
+
|
|
88
|
+
const filteredDfClustersCol = filteredDf.getCol(clustersColName);
|
|
89
|
+
const filteredDfClustersColData = filteredDfClustersCol.getRawData();
|
|
90
|
+
const filteredDfClustersColCategories = filteredDfClustersCol.categories;
|
|
91
|
+
const filteredDfClustersColLength = filteredDfClustersColData.length;
|
|
92
|
+
|
|
93
|
+
// const customClustersColumnsList = wu(this.model.customClusters).toArray();
|
|
94
|
+
const query: { [key: string]: string } = {};
|
|
95
|
+
query[C.TAGS.CUSTOM_CLUSTER] = '1';
|
|
96
|
+
const customClustersColumnsList = wu(filteredDfCols.byTags(query)).filter(c => c.max > 0).toArray();
|
|
97
|
+
const getAggregatedColName = (aggF: string, colName: string) => `${aggF}(${colName})`;
|
|
98
|
+
const isCustomCluster = (cluster: string) => filteredDfCols.contains(cluster);
|
|
99
|
+
|
|
100
|
+
let summaryTableBuilder = filteredDf.groupBy([clustersColName]);
|
|
101
|
+
const aggregateColumnsEntries = Object.entries(this.model.settings.columns ?? {});
|
|
102
|
+
for (const [colName, aggregationFunc] of aggregateColumnsEntries) {
|
|
103
|
+
summaryTableBuilder = summaryTableBuilder.add(
|
|
104
|
+
aggregationFunc as any, colName, getAggregatedColName(aggregationFunc, colName));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const tempSummaryTable = summaryTableBuilder.aggregate();
|
|
108
|
+
const tempSummaryTableLength = tempSummaryTable.rowCount;
|
|
109
|
+
const tempClustersCol: DG.Column<string> = tempSummaryTable.getCol(clustersColName);
|
|
110
|
+
const summaryTableLength = tempSummaryTableLength + customClustersColumnsList.length;
|
|
111
|
+
const summaryTable = DG.DataFrame.create(summaryTableLength);
|
|
112
|
+
const summaryTableCols = summaryTable.columns;
|
|
113
|
+
|
|
114
|
+
const clustersCol = summaryTableCols.addNewString(clustersColName);
|
|
115
|
+
for (let i = 0; i < summaryTableLength; ++i) {
|
|
116
|
+
clustersCol.set(i, i < tempSummaryTableLength ? tempClustersCol.get(i) :
|
|
117
|
+
customClustersColumnsList[i - tempSummaryTableLength].name);
|
|
118
|
+
}
|
|
119
|
+
const clustersColData = clustersCol.getRawData();
|
|
120
|
+
const clustersColCategories = clustersCol.categories;
|
|
121
|
+
|
|
122
|
+
const peptideCol: DG.Column<string> = filteredDf.getCol(this.model.settings.sequenceColumnName!);
|
|
123
|
+
const peptideColData = peptideCol.getRawData();
|
|
124
|
+
const peptideColCategories = peptideCol.categories;
|
|
125
|
+
const peptideColTags = peptideCol.tags;
|
|
126
|
+
|
|
127
|
+
const membersColData = summaryTableCols.addNewInt(C.LST_COLUMN_NAMES.MEMBERS).getRawData();
|
|
128
|
+
const webLogoCol = summaryTableCols.addNewString(C.LST_COLUMN_NAMES.WEB_LOGO);
|
|
129
|
+
const distributionCol = summaryTableCols.addNewString(C.LST_COLUMN_NAMES.DISTRIBUTION);
|
|
130
|
+
const meanDifferenceColData = summaryTableCols.addNewFloat(C.LST_COLUMN_NAMES.MEAN_DIFFERENCE).getRawData();
|
|
131
|
+
const pValColData = summaryTableCols.addNewFloat(C.LST_COLUMN_NAMES.P_VALUE).getRawData();
|
|
132
|
+
const ratioColData = summaryTableCols.addNewFloat(C.LST_COLUMN_NAMES.RATIO).getRawData();
|
|
133
|
+
|
|
134
|
+
for (const [colName, aggregationFunc] of aggregateColumnsEntries) {
|
|
135
|
+
const tempSummaryTableCol = tempSummaryTable.getCol(getAggregatedColName(aggregationFunc, colName));
|
|
136
|
+
const summaryTableCol = summaryTableCols.addNew(tempSummaryTableCol.name, tempSummaryTableCol.type);
|
|
137
|
+
summaryTableCol.init((i) => i < tempSummaryTableLength ? tempSummaryTableCol.get(i) : null);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this.webLogoDfPlot = new Array(summaryTableLength);
|
|
141
|
+
this.distributionDfPlot = new Array(summaryTableLength);
|
|
142
|
+
|
|
143
|
+
for (let summaryTableRowIndex = 0; summaryTableRowIndex < summaryTableLength; ++summaryTableRowIndex) {
|
|
144
|
+
const isOriginalCluster = summaryTableRowIndex < tempSummaryTableLength;
|
|
145
|
+
const currentClusterCategoryIndex = clustersColData[summaryTableRowIndex];
|
|
146
|
+
const currentCluster = clustersColCategories[currentClusterCategoryIndex]; // Cluster name
|
|
147
|
+
const customClusterColData = customClustersColumnsList.find((col) => col.name == currentCluster)?.toList();
|
|
148
|
+
|
|
149
|
+
const isValidIndex = isOriginalCluster ?
|
|
150
|
+
(j: number) => filteredDfClustersColCategories[filteredDfClustersColData[j]] == currentCluster :
|
|
151
|
+
(j: number) => customClusterColData![j];
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
//TODO: use bitset instead of splitCol
|
|
155
|
+
const splitCol = DG.Column.bool(C.COLUMNS_NAMES.SPLIT_COL, activityCol.length);
|
|
156
|
+
const getSplitColValueAt = isOriginalCluster ?
|
|
157
|
+
(splitColIndex: number) => filteredDfClustersColData[splitColIndex] == currentClusterCategoryIndex :
|
|
158
|
+
(splitColIndex: number) => customClusterColData![splitColIndex];
|
|
159
|
+
splitCol.init((i) => getSplitColValueAt(i));
|
|
160
|
+
|
|
161
|
+
let stats: Stats;
|
|
162
|
+
if (isDfFiltered) {
|
|
163
|
+
const trueCount = splitCol.stats.sum;
|
|
164
|
+
const maskInfo = {
|
|
165
|
+
trueCount: trueCount,
|
|
166
|
+
falseCount: activityColData.length - trueCount,
|
|
167
|
+
mask: splitCol.toList() as boolean[],
|
|
168
|
+
};
|
|
169
|
+
stats = getStats(activityColData, maskInfo);
|
|
170
|
+
} else
|
|
171
|
+
stats = this.model.clusterStats[currentCluster];
|
|
172
|
+
|
|
173
|
+
const tCol = DG.Column.string('peptides', stats.count);
|
|
174
|
+
let tColIdx = 0;
|
|
175
|
+
for (let j = 0; j < filteredDfClustersColLength; ++j) {
|
|
176
|
+
if (isValidIndex(j))
|
|
177
|
+
tCol.set(tColIdx++, peptideColCategories[peptideColData[j]]);
|
|
79
178
|
}
|
|
80
|
-
const tCol = DG.Column.string('peptides', indexes.length);
|
|
81
|
-
tCol.init((i) => peptideCol.get(indexes[i]));
|
|
82
179
|
|
|
83
|
-
for (const tag of
|
|
180
|
+
for (const tag of peptideColTags)
|
|
84
181
|
tCol.setTag(tag[0], tag[1]);
|
|
85
182
|
|
|
86
|
-
const uh = new
|
|
87
|
-
tCol.setTag(
|
|
183
|
+
const uh = new UnitsHandler(tCol);
|
|
184
|
+
tCol.setTag(bioTAGS.alphabetSize, uh.getAlphabetSize().toString());
|
|
185
|
+
|
|
88
186
|
|
|
187
|
+
const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
|
|
89
188
|
const dfSlice = DG.DataFrame.fromColumns([tCol]);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
189
|
+
|
|
190
|
+
this.webLogoDfPlot[summaryTableRowIndex] = dfSlice.plot;
|
|
191
|
+
this.distributionDfPlot[summaryTableRowIndex] = distributionTable.plot;
|
|
192
|
+
|
|
193
|
+
membersColData[summaryTableRowIndex] = stats.count;
|
|
194
|
+
meanDifferenceColData[summaryTableRowIndex] = stats.meanDifference;
|
|
195
|
+
pValColData[summaryTableRowIndex] = stats.pValue;
|
|
196
|
+
ratioColData[summaryTableRowIndex] = stats.ratio;
|
|
197
|
+
|
|
198
|
+
//Setting aggregated col values
|
|
199
|
+
if (!isOriginalCluster) {
|
|
200
|
+
for (const [colName, aggregationFunc] of aggregateColumnsEntries) {
|
|
201
|
+
const arrayBuffer = filteredDf.getCol(colName).getRawData();
|
|
202
|
+
const clusterMask = DG.BitSet.fromBytes(arrayBuffer.buffer, arrayBuffer.byteLength / 4);
|
|
203
|
+
const subDf = filteredDf.clone(clusterMask, [colName]);
|
|
204
|
+
const newColName = getAggregatedColName(aggregationFunc, colName);
|
|
205
|
+
const aggregatedDf = subDf.groupBy()
|
|
206
|
+
.add(aggregationFunc as any, colName, newColName)
|
|
207
|
+
.aggregate();
|
|
208
|
+
const value = aggregatedDf.get(newColName, 0);
|
|
209
|
+
summaryTable.set(newColName, summaryTableRowIndex, value);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
96
212
|
}
|
|
97
213
|
webLogoCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
214
|
+
distributionCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
98
215
|
|
|
99
216
|
this.viewerGrid = summaryTable.plot.grid();
|
|
100
|
-
|
|
217
|
+
this.updateFilter();
|
|
218
|
+
const gridClustersCol = this.viewerGrid.col(clustersColName)!;
|
|
101
219
|
gridClustersCol.name = 'Clusters';
|
|
102
220
|
gridClustersCol.visible = true;
|
|
103
221
|
this.viewerGrid.columns.rowHeader!.visible = false;
|
|
104
222
|
this.viewerGrid.props.rowHeight = 55;
|
|
105
223
|
this.viewerGrid.onCellPrepare((cell) => {
|
|
106
|
-
|
|
107
|
-
|
|
224
|
+
const currentRowIdx = cell.tableRowIndex;
|
|
225
|
+
if (!cell.isTableCell || currentRowIdx == null || currentRowIdx == -1)
|
|
226
|
+
return;
|
|
227
|
+
|
|
228
|
+
if (cell.tableColumn?.name == 'WebLogo') {
|
|
229
|
+
this.webLogoDfPlot[currentRowIdx]
|
|
230
|
+
.fromType('WebLogo', {maxHeight: cell.grid.props.rowHeight - 5, positionHeight: this.webLogoMode,
|
|
231
|
+
horizontalAlignment: 'left'})
|
|
108
232
|
.then((viewer) => cell.element = viewer.root);
|
|
233
|
+
} else if (cell.tableColumn?.name == 'Distribution') {
|
|
234
|
+
const viewerRoot = this.distributionDfPlot[currentRowIdx].histogram({
|
|
235
|
+
filteringEnabled: false,
|
|
236
|
+
valueColumnName: C.COLUMNS_NAMES.ACTIVITY_SCALED,
|
|
237
|
+
splitColumnName: C.COLUMNS_NAMES.SPLIT_COL,
|
|
238
|
+
legendVisibility: 'Never',
|
|
239
|
+
showXAxis: true,
|
|
240
|
+
showColumnSelector: false,
|
|
241
|
+
showRangeSlider: false,
|
|
242
|
+
showBinSelector: false,
|
|
243
|
+
backColor: '#fffff',
|
|
244
|
+
}).root;
|
|
245
|
+
|
|
246
|
+
viewerRoot.style.width = 'auto';
|
|
247
|
+
const height = (cell.grid.props.rowHeight - 5) / 2 * 3;
|
|
248
|
+
viewerRoot.style.height = `${height}px`;
|
|
249
|
+
cell.element = viewerRoot;
|
|
109
250
|
}
|
|
110
251
|
});
|
|
111
252
|
this.viewerGrid.root.addEventListener('click', (ev) => {
|
|
112
253
|
const cell = this.viewerGrid.hitTest(ev.offsetX, ev.offsetY);
|
|
113
|
-
if (!cell || !cell.isTableCell)
|
|
254
|
+
if (!cell || !cell.isTableCell || cell.tableColumn?.name != clustersColName)
|
|
114
255
|
return;
|
|
115
256
|
|
|
116
|
-
const cluster = clustersCol.get(cell.tableRowIndex!)!;
|
|
117
257
|
summaryTable.currentRowIdx = -1;
|
|
118
258
|
if (ev.shiftKey)
|
|
119
|
-
this.model.modifyClusterSelection(
|
|
259
|
+
this.model.modifyClusterSelection(cell.cell.value);
|
|
120
260
|
else
|
|
121
|
-
this.model.initClusterSelection(
|
|
261
|
+
this.model.initClusterSelection(cell.cell.value);
|
|
262
|
+
this.viewerGrid.invalidate();
|
|
122
263
|
});
|
|
123
264
|
this.viewerGrid.onCellRender.subscribe((gridCellArgs) => {
|
|
124
265
|
const gc = gridCellArgs.cell;
|
|
125
|
-
if (gc.tableColumn?.name !==
|
|
266
|
+
if (gc.tableColumn?.name !== clustersColName || gc.isColHeader)
|
|
126
267
|
return;
|
|
127
268
|
const canvasContext = gridCellArgs.g;
|
|
128
269
|
const bound = gridCellArgs.bounds;
|
|
@@ -135,8 +276,8 @@ export class LogoSummary extends DG.JsViewer {
|
|
|
135
276
|
canvasContext.restore();
|
|
136
277
|
});
|
|
137
278
|
this.viewerGrid.onCellTooltip((cell, x, y) => {
|
|
138
|
-
if (!cell.isColHeader && cell.tableColumn?.name ===
|
|
139
|
-
this.model.showTooltipCluster(cell.cell.
|
|
279
|
+
if (!cell.isColHeader && cell.tableColumn?.name === clustersColName)
|
|
280
|
+
this.model.showTooltipCluster(cell.cell.rowIndex, x, y, cell.cell.value);
|
|
140
281
|
return true;
|
|
141
282
|
});
|
|
142
283
|
const webLogoGridCol = this.viewerGrid.columns.byName('WebLogo')!;
|
|
@@ -151,4 +292,97 @@ export class LogoSummary extends DG.JsViewer {
|
|
|
151
292
|
|
|
152
293
|
return this.viewerGrid;
|
|
153
294
|
}
|
|
295
|
+
|
|
296
|
+
updateFilter(): void {
|
|
297
|
+
const table = this.viewerGrid.table;
|
|
298
|
+
const memberstCol = table.getCol(C.LST_COLUMN_NAMES.MEMBERS);
|
|
299
|
+
const membersColData = memberstCol.getRawData();
|
|
300
|
+
const maxCount = memberstCol.stats.max;
|
|
301
|
+
const minMembers = Math.ceil(maxCount * this.membersRatioThreshold);
|
|
302
|
+
table.filter.init((i) => membersColData[i] > minMembers);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
clusterFromSelection(): void {
|
|
306
|
+
const filteredDf = this.dataFrame.filter.anyFalse ? this.dataFrame.clone(this.dataFrame.filter, null, true) :
|
|
307
|
+
this.dataFrame;
|
|
308
|
+
const selection = filteredDf.selection;
|
|
309
|
+
const viewerDf = this.viewerGrid.dataFrame;
|
|
310
|
+
const viewerDfCols = viewerDf.columns;
|
|
311
|
+
const viewerDfColsLength = viewerDfCols.length;
|
|
312
|
+
const newClusterVals = new Array(viewerDfCols.length);
|
|
313
|
+
|
|
314
|
+
const activityScaledCol = filteredDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
315
|
+
const maskInfo: MaskInfo = {
|
|
316
|
+
mask: selection.getBuffer(),
|
|
317
|
+
trueCount: selection.trueCount,
|
|
318
|
+
falseCount: selection.falseCount,
|
|
319
|
+
};
|
|
320
|
+
const stats = getStats(activityScaledCol.getRawData(), maskInfo);
|
|
321
|
+
const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, filteredDf.getCol(this.model.splitCol.name)]);
|
|
322
|
+
|
|
323
|
+
const peptideCol: DG.Column<string> = filteredDf.getCol(this.model.settings.sequenceColumnName!);
|
|
324
|
+
const peptideColData = peptideCol.getRawData();
|
|
325
|
+
const peptideColCategories = peptideCol.categories;
|
|
326
|
+
const peptideColTags = peptideCol.tags;
|
|
327
|
+
const selectedIndexes = selection.getSelectedIndexes();
|
|
328
|
+
const tCol = DG.Column.string('peptides', selectedIndexes.length);
|
|
329
|
+
|
|
330
|
+
for (let i = 0; i < selectedIndexes.length; ++i)
|
|
331
|
+
tCol.set(i, peptideColCategories[peptideColData[selectedIndexes[i]]]);
|
|
332
|
+
for (const tag of peptideColTags)
|
|
333
|
+
tCol.setTag(tag[0], tag[1]);
|
|
334
|
+
|
|
335
|
+
const uh = new UnitsHandler(tCol);
|
|
336
|
+
tCol.setTag(bioTAGS.alphabetSize, uh.getAlphabetSize().toString());
|
|
337
|
+
|
|
338
|
+
const webLogoTable = DG.DataFrame.fromColumns([tCol]);
|
|
339
|
+
this.webLogoDfPlot.push(webLogoTable.plot);
|
|
340
|
+
this.distributionDfPlot.push(distributionTable.plot);
|
|
341
|
+
|
|
342
|
+
const colCategories = viewerDfCols.byName(this.model.settings.clustersColumnName!).categories;
|
|
343
|
+
let newClusterName = this.newClusterName;
|
|
344
|
+
let clusterNum = 1;
|
|
345
|
+
const getString = !isNaN(parseInt(newClusterName)) ? () => `${parseInt(newClusterName) + 1}` :
|
|
346
|
+
newClusterName == '' ? () => `${clusterNum++}` :
|
|
347
|
+
() => `${this.newClusterName} ${clusterNum++}`;
|
|
348
|
+
while (colCategories.includes(newClusterName))
|
|
349
|
+
newClusterName = getString();
|
|
350
|
+
|
|
351
|
+
this.getProperty('newClusterName')?.set(this, getString());
|
|
352
|
+
|
|
353
|
+
for (let i = 0; i < viewerDfColsLength; ++i) {
|
|
354
|
+
const col = viewerDfCols.byIndex(i);
|
|
355
|
+
newClusterVals[i] = col.name == this.model.settings.clustersColumnName! ? newClusterName :
|
|
356
|
+
col.name == C.LST_COLUMN_NAMES.MEMBERS ? maskInfo.trueCount :
|
|
357
|
+
col.name == C.LST_COLUMN_NAMES.WEB_LOGO ? null :
|
|
358
|
+
col.name == C.LST_COLUMN_NAMES.DISTRIBUTION ? null :
|
|
359
|
+
col.name == C.LST_COLUMN_NAMES.MEAN_DIFFERENCE ? stats.meanDifference:
|
|
360
|
+
col.name == C.LST_COLUMN_NAMES.P_VALUE ? stats.pValue:
|
|
361
|
+
col.name == C.LST_COLUMN_NAMES.RATIO ? stats.ratio:
|
|
362
|
+
console.warn(`PeptidesLSTWarn: value for column ${col.name} is undefined`)! || null;
|
|
363
|
+
}
|
|
364
|
+
viewerDf.rows.addNew(newClusterVals);
|
|
365
|
+
|
|
366
|
+
this.model.clusterStats[newClusterName] = stats;
|
|
367
|
+
this.model.addNewCluster(newClusterName);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
removeCluster(): void {
|
|
371
|
+
const lss = this.model.logoSummarySelection;
|
|
372
|
+
const dfCols = this.dataFrame.columns;
|
|
373
|
+
|
|
374
|
+
const removeClusterIndexesList = lss.filter((cluster) => dfCols.contains(cluster));
|
|
375
|
+
if (removeClusterIndexesList.length == 0)
|
|
376
|
+
return grok.shell.info('Nothing removed. Please select a created cluster to remove');
|
|
377
|
+
|
|
378
|
+
for (const cluster of removeClusterIndexesList) {
|
|
379
|
+
lss.splice(lss.indexOf(cluster), 1);
|
|
380
|
+
dfCols.remove(cluster);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
this.model.logoSummarySelection = lss;
|
|
384
|
+
this.model.clusterStats = this.model.calculateClusterStatistics();
|
|
385
|
+
this.createLogoSummaryGrid();
|
|
386
|
+
this.render();
|
|
387
|
+
}
|
|
154
388
|
}
|
|
@@ -40,7 +40,7 @@ export class PeptideSpaceViewer extends DG.JsViewer {
|
|
|
40
40
|
async onTableAttached(): Promise<void> {
|
|
41
41
|
super.onTableAttached();
|
|
42
42
|
|
|
43
|
-
this.model =
|
|
43
|
+
this.model = PeptidesModel.getInstance(this.dataFrame);
|
|
44
44
|
|
|
45
45
|
await this.render(!this.dataFrame.temp[C.EMBEDDING_STATUS]);
|
|
46
46
|
}
|
|
@@ -62,7 +62,7 @@ export class PeptideSpaceViewer extends DG.JsViewer {
|
|
|
62
62
|
$(this.root).empty();
|
|
63
63
|
const viewerHost = ui.waitBox(async () => {
|
|
64
64
|
// const aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
|
|
65
|
-
const alignedSeqCol = this.dataFrame.getCol(
|
|
65
|
+
const alignedSeqCol = this.dataFrame.getCol(this.model.settings.sequenceColumnName!);
|
|
66
66
|
const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, alignedSeqCol);
|
|
67
67
|
this.dataFrame.temp[C.EMBEDDING_STATUS] = true;
|
|
68
68
|
this.model.edf = edf;
|
|
@@ -77,7 +77,7 @@ export class PeptideSpaceViewer extends DG.JsViewer {
|
|
|
77
77
|
this.model.fireBitsetChanged(true);
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
const colorCol = this.dataFrame.
|
|
80
|
+
const colorCol = this.dataFrame.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
81
81
|
edf.columns.add(colorCol);
|
|
82
82
|
|
|
83
83
|
const viewerOptions = {
|
|
@@ -112,14 +112,14 @@ export class PeptideSpaceViewer extends DG.JsViewer {
|
|
|
112
112
|
|
|
113
113
|
//Do not accept table, only column
|
|
114
114
|
export async function computeWeights(
|
|
115
|
-
table: DG.DataFrame, method: string, measure: string, cyclesCount: number, col
|
|
115
|
+
table: DG.DataFrame, method: string, measure: string, cyclesCount: number, col: DG.Column,
|
|
116
116
|
): Promise<DG.DataFrame | null> {
|
|
117
117
|
const pi = DG.TaskBarProgressIndicator.create('Creating embedding...');
|
|
118
118
|
let edf: DG.DataFrame | null = null;
|
|
119
119
|
try {
|
|
120
120
|
const axesNames = ['~X', '~Y', '~MW'];
|
|
121
121
|
// col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
|
|
122
|
-
col ??= table.getCol(
|
|
122
|
+
// col ??= table.getCol(this.model.settings.sequenceColumnName!);
|
|
123
123
|
const columnData = col.toList().map((v) => AlignedSequenceEncoder.clean(v));
|
|
124
124
|
|
|
125
125
|
const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
|