@datagrok/peptides 0.8.13 → 1.0.0
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 +1268 -1766
- package/dist/package.js +1097 -1622
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +120 -62
- package/package.json +13 -17
- package/package.png +0 -0
- package/src/model.ts +504 -448
- package/src/monomer-library.ts +31 -30
- package/src/package-test.ts +5 -6
- package/src/package.ts +52 -70
- package/src/tests/core.ts +67 -0
- package/src/tests/msa-tests.ts +3 -3
- package/src/tests/peptide-space-test.ts +65 -45
- package/src/tests/utils.ts +20 -50
- package/src/utils/cell-renderer.ts +25 -151
- package/src/utils/chem-palette.ts +3 -14
- package/src/utils/constants.ts +5 -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 +5 -2
- package/src/viewers/peptide-space-viewer.ts +67 -39
- package/src/viewers/sar-viewer.ts +34 -37
- package/src/viewers/stacked-barchart-viewer.ts +38 -61
- package/src/widgets/analyze-peptides.ts +53 -75
- package/src/widgets/distribution.ts +34 -18
- package/src/widgets/manual-alignment.ts +8 -12
- package/src/widgets/peptide-molecule.ts +48 -25
- package/src/widgets/subst-table.ts +53 -52
- package/src/workers/dimensionality-reducer.ts +8 -13
- package/{test-Peptides-f8114def7953-4bf59d70.html → test-Peptides-69a4761f6044-40ac3a0c.html} +2 -2
- 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
package/src/model.ts
CHANGED
|
@@ -4,7 +4,6 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {Subject, Observable} from 'rxjs';
|
|
6
6
|
import {addViewerToHeader, StackedBarChart} from './viewers/stacked-barchart-viewer';
|
|
7
|
-
import {PeptidesController} from './peptides';
|
|
8
7
|
import {tTest} from '@datagrok-libraries/statistics/src/tests';
|
|
9
8
|
import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests';
|
|
10
9
|
import {ChemPalette} from './utils/chem-palette';
|
|
@@ -12,22 +11,28 @@ import {MonomerLibrary} from './monomer-library';
|
|
|
12
11
|
import * as C from './utils/constants';
|
|
13
12
|
import * as type from './utils/types';
|
|
14
13
|
import {FilteringStatistics} from './utils/filtering-statistics';
|
|
14
|
+
import {getSeparator, getTypedArrayConstructor, stringToBool} from './utils/misc';
|
|
15
|
+
import {_package} from './package';
|
|
16
|
+
import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
|
|
17
|
+
import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
|
|
18
|
+
import {setAARRenderer} from './utils/cell-renderer';
|
|
19
|
+
import {substitutionsWidget} from './widgets/subst-table';
|
|
20
|
+
import {getDistributionWidget} from './widgets/distribution';
|
|
15
21
|
|
|
16
22
|
export class PeptidesModel {
|
|
17
23
|
static _modelName = 'peptidesModel';
|
|
18
|
-
|
|
24
|
+
|
|
19
25
|
_statsDataFrameSubject = new Subject<DG.DataFrame>();
|
|
20
26
|
_sarGridSubject = new Subject<DG.Grid>();
|
|
21
27
|
_sarVGridSubject = new Subject<DG.Grid>();
|
|
22
|
-
|
|
23
|
-
_substitutionTableSubject = new Subject<DG.DataFrame>();
|
|
28
|
+
_substitutionTableSubject = new Subject<type.SubstitutionsInfo>();
|
|
24
29
|
|
|
25
30
|
_isUpdating: boolean = false;
|
|
26
31
|
_isSubstInitialized = false;
|
|
27
32
|
isBitsetChangedInitialized = false;
|
|
33
|
+
isCellChanging = false;
|
|
28
34
|
|
|
29
35
|
//viewer properties
|
|
30
|
-
// _grouping!: boolean;
|
|
31
36
|
_filterMode!: boolean;
|
|
32
37
|
_twoColorMode!: boolean;
|
|
33
38
|
_activityScaling!: string;
|
|
@@ -39,79 +44,107 @@ export class PeptidesModel {
|
|
|
39
44
|
_sarVGrid!: DG.Grid;
|
|
40
45
|
_sourceGrid!: DG.Grid;
|
|
41
46
|
_dataFrame: DG.DataFrame;
|
|
42
|
-
|
|
43
|
-
splitCol!: DG.Column;
|
|
47
|
+
splitCol!: DG.Column<boolean>;
|
|
44
48
|
stackedBarchart!: StackedBarChart;
|
|
49
|
+
edf: DG.DataFrame | null = null;
|
|
50
|
+
|
|
51
|
+
substitutionsInfo: type.SubstitutionsInfo = new Map();
|
|
52
|
+
isInitialized: boolean = false;
|
|
53
|
+
currentView!: DG.TableView;
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
_currentSelection!: type.SelectionObject;
|
|
56
|
+
isPeptideSpaceChangingBitset: boolean = false;
|
|
57
|
+
isChangingEdfBitset: boolean = false;
|
|
49
58
|
|
|
50
59
|
private constructor(dataFrame: DG.DataFrame) {
|
|
51
60
|
this._dataFrame = dataFrame;
|
|
52
|
-
this._dataFrame.temp[C.PEPTIDES_ANALYSIS] = true;
|
|
53
|
-
|
|
54
61
|
this.updateProperties();
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
static getInstance(dataFrame: DG.DataFrame): PeptidesModel {
|
|
64
|
+
static async getInstance(dataFrame: DG.DataFrame, dgPackage?: DG.Package): Promise<PeptidesModel> {
|
|
65
|
+
if (dataFrame.temp[MonomerLibrary.id] === null) {
|
|
66
|
+
const sdf = await (dgPackage ?? _package).files.readAsText('HELMMonomers_June10.sdf');
|
|
67
|
+
dataFrame.temp[MonomerLibrary.id] ??= new MonomerLibrary(sdf);
|
|
68
|
+
}
|
|
58
69
|
dataFrame.temp[PeptidesModel.modelName] ??= new PeptidesModel(dataFrame);
|
|
59
|
-
|
|
70
|
+
await (dataFrame.temp[PeptidesModel.modelName] as PeptidesModel).init();
|
|
71
|
+
return dataFrame.temp[PeptidesModel.modelName] as PeptidesModel;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static get modelName(): string {return PeptidesModel._modelName;}
|
|
75
|
+
|
|
76
|
+
static get chemPalette(): typeof ChemPalette {return ChemPalette;}
|
|
77
|
+
|
|
78
|
+
get onStatsDataFrameChanged(): Observable<DG.DataFrame> {return this._statsDataFrameSubject.asObservable();}
|
|
79
|
+
|
|
80
|
+
get onSARGridChanged(): Observable<DG.Grid> {return this._sarGridSubject.asObservable();}
|
|
81
|
+
|
|
82
|
+
get onSARVGridChanged(): Observable<DG.Grid> {return this._sarVGridSubject.asObservable();}
|
|
83
|
+
|
|
84
|
+
get onSubstTableChanged(): Observable<type.SubstitutionsInfo> {return this._substitutionTableSubject.asObservable();}
|
|
85
|
+
|
|
86
|
+
get currentSelection(): type.SelectionObject {
|
|
87
|
+
this._currentSelection ??= JSON.parse(this._dataFrame.tags[C.TAGS.SELECTION] || '{}');
|
|
88
|
+
return this._currentSelection;
|
|
89
|
+
}
|
|
90
|
+
set currentSelection(selection: type.SelectionObject) {
|
|
91
|
+
this._currentSelection = selection;
|
|
92
|
+
this._dataFrame.tags[C.TAGS.SELECTION] = JSON.stringify(selection);
|
|
93
|
+
this.invalidateSelection();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
invalidateSelection(): void {
|
|
97
|
+
this.fireBitsetChanged();
|
|
98
|
+
this.invalidateGrids();
|
|
60
99
|
}
|
|
61
100
|
|
|
62
|
-
|
|
101
|
+
createAccordion() {
|
|
102
|
+
const acc = ui.accordion('Selection info');
|
|
103
|
+
acc.root.style.width = '100%';
|
|
104
|
+
acc.addTitle(ui.h1('Selection info'));
|
|
105
|
+
acc.addPane('Substitutions', () => substitutionsWidget(this._dataFrame, this).root, true);
|
|
106
|
+
acc.addPane('Distribtution', () => getDistributionWidget(this._dataFrame).root, true);
|
|
107
|
+
|
|
108
|
+
return acc;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
updateProperties(): void {
|
|
63
112
|
this._activityScaling = this._dataFrame.tags['scaling'];
|
|
64
|
-
this._filterMode =
|
|
65
|
-
this._twoColorMode =
|
|
66
|
-
|
|
67
|
-
this._isSubstitutionOn = this.stringToBool(this._dataFrame.tags['showSubstitution']);
|
|
113
|
+
this._filterMode = stringToBool(this._dataFrame.tags['filterMode']);
|
|
114
|
+
this._twoColorMode = stringToBool(this._dataFrame.tags['bidirectionalAnalysis']);
|
|
115
|
+
this._isSubstitutionOn = stringToBool(this._dataFrame.tags['showSubstitution']);
|
|
68
116
|
this._maxSubstitutions = parseInt(this._dataFrame.tags['maxSubstitutions']);
|
|
69
117
|
this._activityLimit = parseFloat(this._dataFrame.tags['activityLimit']);
|
|
70
118
|
}
|
|
71
119
|
|
|
72
|
-
stringToBool(str: string) {
|
|
73
|
-
return str === 'true' ? true : false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
120
|
setProperties(
|
|
77
121
|
activityScaling: string, filterMode: boolean, twoColorMode: boolean, isSubstitutionOn: boolean,
|
|
78
122
|
maxSubstitutions: number, activityLimit: number, forceUpdate = false,
|
|
79
|
-
) {
|
|
80
|
-
const chooseAction =
|
|
123
|
+
): void {
|
|
124
|
+
const chooseAction =
|
|
125
|
+
(value: string, defaultValue: string | boolean | number): string | boolean | number =>
|
|
126
|
+
forceUpdate ? value : defaultValue ?? value;
|
|
81
127
|
this._dataFrame.tags['scaling'] = chooseAction(`${activityScaling}`, this._dataFrame.tags['scaling']);
|
|
82
128
|
this._dataFrame.tags['filterMode'] = chooseAction(`${filterMode}`, this._dataFrame.tags['filterMode']);
|
|
83
|
-
this._dataFrame.tags['bidirectionalAnalysis'] =
|
|
84
|
-
|
|
85
|
-
this._dataFrame.tags['showSubstitution'] =
|
|
86
|
-
|
|
129
|
+
this._dataFrame.tags['bidirectionalAnalysis'] =
|
|
130
|
+
chooseAction(`${twoColorMode}`, this._dataFrame.tags['bidirectionalAnalysis']);
|
|
131
|
+
this._dataFrame.tags['showSubstitution'] =
|
|
132
|
+
chooseAction(`${isSubstitutionOn}`, this._dataFrame.tags['showSubstitution']);
|
|
133
|
+
this._dataFrame.tags['maxSubstitutions'] =
|
|
134
|
+
chooseAction(`${maxSubstitutions}`, this._dataFrame.tags['maxSubstitutions']);
|
|
87
135
|
this._dataFrame.tags['activityLimit'] = chooseAction(`${activityLimit}`, this._dataFrame.tags['activityLimit']);
|
|
88
|
-
|
|
136
|
+
|
|
89
137
|
this.updateProperties();
|
|
90
138
|
}
|
|
91
139
|
|
|
92
|
-
get dataFrame(): DG.DataFrame {return this._dataFrame;}
|
|
93
|
-
|
|
94
|
-
get onStatsDataFrameChanged(): Observable<DG.DataFrame> {return this._statsDataFrameSubject.asObservable();}
|
|
95
|
-
|
|
96
|
-
get onSARGridChanged(): Observable<DG.Grid> {return this._sarGridSubject.asObservable();}
|
|
97
|
-
|
|
98
|
-
get onSARVGridChanged(): Observable<DG.Grid> {return this._sarVGridSubject.asObservable();}
|
|
99
|
-
|
|
100
|
-
// get onGroupMappingChanged(): Observable<StringDictionary> {return this._groupMappingSubject.asObservable();}
|
|
101
|
-
|
|
102
|
-
get onSubstTableChanged(): Observable<DG.DataFrame> {return this._substitutionTableSubject.asObservable();}
|
|
103
|
-
|
|
104
|
-
get substTooltipData(): type.SubstitutionTooltips {return this._substTableTooltipData!;}
|
|
105
|
-
|
|
106
140
|
async updateData(
|
|
107
|
-
activityScaling?: string, sourceGrid?: DG.Grid, twoColorMode?: boolean,
|
|
141
|
+
activityScaling?: string, sourceGrid?: DG.Grid, twoColorMode?: boolean, activityLimit?: number,
|
|
108
142
|
maxSubstitutions?: number, isSubstitutionOn?: boolean, filterMode?: boolean,
|
|
109
|
-
) {
|
|
143
|
+
): Promise<void> {
|
|
110
144
|
//FIXME: threre are too many assignments, some are duplicating
|
|
111
145
|
this._activityScaling = activityScaling ?? this._activityScaling;
|
|
112
146
|
this._sourceGrid = sourceGrid ?? this._sourceGrid;
|
|
113
147
|
this._twoColorMode = twoColorMode ?? this._twoColorMode;
|
|
114
|
-
// this._grouping = grouping ?? this._grouping;
|
|
115
148
|
this._activityLimit = activityLimit ?? this._activityLimit;
|
|
116
149
|
this._maxSubstitutions = maxSubstitutions ?? this._maxSubstitutions;
|
|
117
150
|
this._isSubstitutionOn = isSubstitutionOn ?? this._isSubstitutionOn;
|
|
@@ -122,81 +155,68 @@ export class PeptidesModel {
|
|
|
122
155
|
await this.updateDefault();
|
|
123
156
|
}
|
|
124
157
|
|
|
125
|
-
async updateDefault() {
|
|
158
|
+
async updateDefault(): Promise<void> {
|
|
126
159
|
if (this._activityScaling && this._sourceGrid && this._twoColorMode !== null && !this._isUpdating) {
|
|
127
160
|
this._isUpdating = true;
|
|
128
|
-
const [viewerGrid, viewerVGrid, statsDf
|
|
161
|
+
const [viewerGrid, viewerVGrid, statsDf] = await this.initializeViewersComponents();
|
|
129
162
|
//FIXME: modify during the initializeViewersComponents stages
|
|
130
163
|
this._statsDataFrameSubject.next(statsDf);
|
|
131
|
-
// this._groupMappingSubject.next(groupMapping);
|
|
132
164
|
this._sarGridSubject.next(viewerGrid);
|
|
133
165
|
this._sarVGridSubject.next(viewerVGrid);
|
|
134
166
|
if (this._isSubstitutionOn) {
|
|
135
|
-
this._substitutionTableSubject.next(
|
|
167
|
+
this._substitutionTableSubject.next(this.substitutionsInfo);
|
|
136
168
|
this._isSubstInitialized = true;
|
|
137
169
|
}
|
|
138
170
|
}
|
|
139
171
|
await this.updateBarchart();
|
|
140
|
-
this.
|
|
172
|
+
this.invalidateSelection();
|
|
141
173
|
|
|
142
174
|
this._isUpdating = false;
|
|
143
175
|
}
|
|
144
176
|
|
|
145
|
-
async updateBarchart() {
|
|
177
|
+
async updateBarchart(): Promise<void> {
|
|
146
178
|
this.stackedBarchart ??= await this._dataFrame?.plot.fromType('StackedBarChartAA') as StackedBarChart;
|
|
147
179
|
if (this.stackedBarchart && this._sourceGrid)
|
|
148
180
|
addViewerToHeader(this._sourceGrid, this.stackedBarchart);
|
|
149
181
|
}
|
|
150
182
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
async initializeViewersComponents(): Promise<[DG.Grid, DG.Grid, DG.DataFrame, DG.DataFrame]> {
|
|
183
|
+
async initializeViewersComponents(): Promise<[DG.Grid, DG.Grid, DG.DataFrame]> {
|
|
154
184
|
if (this._sourceGrid === null)
|
|
155
185
|
throw new Error(`Source grid is not initialized`);
|
|
156
186
|
|
|
157
187
|
//Split the aligned sequence into separate AARs
|
|
158
188
|
let splitSeqDf: DG.DataFrame | undefined;
|
|
159
189
|
let invalidIndexes: number[];
|
|
160
|
-
const col: DG.Column =
|
|
161
|
-
[splitSeqDf, invalidIndexes] =
|
|
190
|
+
const col: DG.Column = this._dataFrame.columns.bySemType(C.SEM_TYPES.ALIGNED_SEQUENCE)!;
|
|
191
|
+
[splitSeqDf, invalidIndexes] = PeptidesModel.splitAlignedPeptides(col);
|
|
162
192
|
|
|
163
|
-
const positionColumns =
|
|
164
|
-
const renderColNames: string[] =
|
|
193
|
+
const positionColumns = splitSeqDf.columns.names();
|
|
194
|
+
const renderColNames: string[] = splitSeqDf.columns.names();
|
|
165
195
|
|
|
166
|
-
|
|
196
|
+
const activityCol = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY)!;
|
|
197
|
+
splitSeqDf.columns.add(activityCol);
|
|
167
198
|
|
|
168
|
-
this.joinDataFrames(
|
|
199
|
+
this.joinDataFrames(positionColumns, splitSeqDf);
|
|
169
200
|
|
|
170
|
-
for (const dfCol of
|
|
171
|
-
if (
|
|
172
|
-
|
|
201
|
+
for (const dfCol of this._dataFrame.columns) {
|
|
202
|
+
if (positionColumns.includes(dfCol.name))
|
|
203
|
+
setAARRenderer(dfCol, this._sourceGrid);
|
|
173
204
|
}
|
|
174
205
|
|
|
175
206
|
this.sortSourceGrid(this._sourceGrid);
|
|
176
207
|
|
|
177
|
-
await this.createScaledCol(this._activityScaling
|
|
208
|
+
await this.createScaledCol(this._activityScaling, this._dataFrame, this._sourceGrid, splitSeqDf);
|
|
178
209
|
|
|
179
210
|
//unpivot a table and handle duplicates
|
|
180
211
|
splitSeqDf = splitSeqDf.groupBy(positionColumns)
|
|
181
212
|
.add('med', C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.ACTIVITY_SCALED)
|
|
182
213
|
.aggregate();
|
|
183
214
|
|
|
184
|
-
const peptidesCount = splitSeqDf.
|
|
215
|
+
const peptidesCount = splitSeqDf.rowCount;
|
|
185
216
|
|
|
186
217
|
let matrixDf = splitSeqDf.unpivot(
|
|
187
218
|
[C.COLUMNS_NAMES.ACTIVITY_SCALED], positionColumns, C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
188
219
|
|
|
189
|
-
//TODO: move to chem palette
|
|
190
|
-
// let groupMapping: StringDictionary = {};
|
|
191
|
-
// if (this._grouping) {
|
|
192
|
-
// groupMapping = C.aarGroups;
|
|
193
|
-
// const aarCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
194
|
-
// aarCol.init((index) => groupMapping[aarCol.get(index)[0]] ?? '-');
|
|
195
|
-
// aarCol.compact();
|
|
196
|
-
// } else
|
|
197
|
-
// Object.keys(C.aarGroups).forEach((value) => groupMapping[value] = value);
|
|
198
|
-
|
|
199
|
-
|
|
200
220
|
//FIXME: for some reason Mean difference is not calculated for all the AARs
|
|
201
221
|
//statistics for specific AAR at a specific position
|
|
202
222
|
const statsDf = await this.calculateStatistics(matrixDf, peptidesCount, splitSeqDf);
|
|
@@ -210,15 +230,15 @@ export class PeptidesModel {
|
|
|
210
230
|
matrixDf.name = 'SAR';
|
|
211
231
|
|
|
212
232
|
// Setting category order
|
|
213
|
-
await this.setCategoryOrder(this._twoColorMode
|
|
233
|
+
await this.setCategoryOrder(this._twoColorMode, statsDf, matrixDf);
|
|
214
234
|
|
|
215
235
|
// SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
|
|
216
|
-
const sequenceDf = this.createVerticalTable(statsDf, this._twoColorMode
|
|
236
|
+
const sequenceDf = this.createVerticalTable(statsDf, this._twoColorMode);
|
|
217
237
|
renderColNames.push(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
218
238
|
|
|
219
|
-
|
|
239
|
+
|
|
220
240
|
if (this._isSubstitutionOn || !this._isSubstInitialized)
|
|
221
|
-
|
|
241
|
+
this.calcSubstitutions();
|
|
222
242
|
|
|
223
243
|
//TODO: move everything below out to controller
|
|
224
244
|
const [sarGrid, sarVGrid] = this.createGrids(matrixDf, positionColumns, sequenceDf);
|
|
@@ -234,165 +254,112 @@ export class PeptidesModel {
|
|
|
234
254
|
|
|
235
255
|
this.setInteractionCallback();
|
|
236
256
|
|
|
237
|
-
this.modifyOrCreateSplitCol(C.CATEGORIES.ALL, C.CATEGORIES.ALL);
|
|
238
|
-
|
|
239
257
|
this.setBitsetCallback();
|
|
240
258
|
|
|
241
259
|
this.postProcessGrids(this._sourceGrid, invalidIndexes, sarGrid, sarVGrid);
|
|
242
260
|
|
|
243
|
-
if (this.dataFrame.tags[C.TAGS.AAR] && this.dataFrame.tags[C.TAGS.POSITION]) {
|
|
244
|
-
const sarDf = sarGrid.dataFrame;
|
|
245
|
-
const rowCount = sarDf.rowCount;
|
|
246
|
-
let index = -1;
|
|
247
|
-
for (let i = 0; i < rowCount; i++) {
|
|
248
|
-
if (sarDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, i) === this.dataFrame.tags[C.TAGS.AAR]) {
|
|
249
|
-
index = i;
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
sarDf.currentCell = sarDf.cell(index, this.dataFrame.tags[C.TAGS.POSITION]);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
261
|
//TODO: return class instead
|
|
257
|
-
return [sarGrid, sarVGrid, statsDf
|
|
262
|
+
return [sarGrid, sarVGrid, statsDf];
|
|
258
263
|
}
|
|
259
264
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
// const splitedMatrix = this.split(col);
|
|
265
|
-
const columnList = (this.dataFrame.columns as DG.ColumnList).toList()
|
|
266
|
-
.filter(col => col.semType === C.SEM_TYPES.AMINO_ACIDS);
|
|
267
|
-
if (columnList.length === 0)
|
|
268
|
-
throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.AMINO_ACIDS}'`);
|
|
269
|
-
|
|
270
|
-
const tableValues: { [aar: string]: number[]; } = {};
|
|
271
|
-
const tableTooltips: { [aar: string]: {}[][]; } = {};
|
|
272
|
-
const tableCases: { [aar: string]: number[][][]; } = {};
|
|
273
|
-
|
|
274
|
-
// const nRows = splitedMatrix.length;
|
|
275
|
-
// const nCols = splitedMatrix[0].length;
|
|
276
|
-
// const nColsArray = Array(nCols);
|
|
265
|
+
//TODO: move to controller?
|
|
266
|
+
calcSubstitutions(): void {
|
|
267
|
+
const activityValues: DG.Column<number> = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
268
|
+
const columnList: DG.Column<string>[] = this._dataFrame.columns.bySemTypeAll(C.SEM_TYPES.AMINO_ACIDS);
|
|
277
269
|
const nCols = columnList.length;
|
|
278
|
-
|
|
270
|
+
if (nCols == 0)
|
|
271
|
+
throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.AMINO_ACIDS}'`);
|
|
279
272
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
273
|
+
this.substitutionsInfo = new Map();
|
|
274
|
+
const nRows = this._dataFrame.rowCount;
|
|
275
|
+
for (let seq1Idx = 0; seq1Idx < nRows - 1; seq1Idx++) {
|
|
276
|
+
for (let seq2Idx = seq1Idx + 1; seq2Idx < nRows; seq2Idx++) {
|
|
283
277
|
let substCounter = 0;
|
|
284
|
-
const
|
|
285
|
-
const
|
|
286
|
-
const
|
|
287
|
-
const activityValJ = activityValues.get(j) as number;
|
|
288
|
-
const strActivityValI = activityValI.toFixed(2);
|
|
289
|
-
const strActivityValJ = activityValJ.toFixed(2);
|
|
290
|
-
const delta = activityValI - activityValJ;
|
|
291
|
-
|
|
278
|
+
const activityValSeq1 = activityValues.get(seq1Idx);
|
|
279
|
+
const activityValSeq2 = activityValues.get(seq2Idx);
|
|
280
|
+
const delta = activityValSeq1 - activityValSeq2;
|
|
292
281
|
if (Math.abs(delta) < this._activityLimit)
|
|
293
282
|
continue;
|
|
294
283
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
if (
|
|
284
|
+
let substCounterFlag = false;
|
|
285
|
+
const tempData: {pos: string, seq1monomer: string, seq2monomer: string, seq1Idx: number, seq2Idx: number}[] =
|
|
286
|
+
[];
|
|
287
|
+
for (const currentPosCol of columnList) {
|
|
288
|
+
const seq1monomer = currentPosCol.get(seq1Idx);
|
|
289
|
+
const seq2monomer = currentPosCol.get(seq2Idx);
|
|
290
|
+
if (seq1monomer == seq2monomer)
|
|
302
291
|
continue;
|
|
303
292
|
|
|
304
293
|
substCounter++;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
key: `${smjk === '-' ? 'Empty' : smjk} → ${smik === '-' ? 'Empty' : smik}`,
|
|
317
|
-
value: `${strActivityValJ} → ${strActivityValI}`,
|
|
318
|
-
diff: delta,
|
|
319
|
-
},
|
|
320
|
-
];
|
|
294
|
+
substCounterFlag = substCounter > this._maxSubstitutions;
|
|
295
|
+
if (substCounterFlag)
|
|
296
|
+
break;
|
|
297
|
+
|
|
298
|
+
tempData.push({
|
|
299
|
+
pos: currentPosCol.name,
|
|
300
|
+
seq1monomer: seq1monomer,
|
|
301
|
+
seq2monomer: seq2monomer,
|
|
302
|
+
seq1Idx: seq1Idx,
|
|
303
|
+
seq2Idx: seq2Idx,
|
|
304
|
+
});
|
|
321
305
|
}
|
|
322
306
|
|
|
323
|
-
if (
|
|
307
|
+
if (substCounterFlag || substCounter == 0)
|
|
324
308
|
continue;
|
|
325
309
|
|
|
326
|
-
for (const
|
|
327
|
-
|
|
328
|
-
const posInt = parseInt(pos);
|
|
329
|
-
const aar = subst[posInt][0];
|
|
330
|
-
if (!Object.keys(tableValues).includes(aar)) {
|
|
331
|
-
// tableValues[aar] = Array(...nColsArray).map(() => DG.INT_NULL);
|
|
332
|
-
// tableTooltips[aar] = Array(...nColsArray).map(() => []);
|
|
333
|
-
// tableCases[aar] = Array(...nColsArray).map(() => []);
|
|
334
|
-
tableValues[aar] = Array(nCols).fill(DG.INT_NULL);
|
|
335
|
-
tableTooltips[aar] = Array(nCols).fill([]);
|
|
336
|
-
tableCases[aar] = Array(nCols).fill([]);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
tableValues[aar][posInt] = tableValues[aar][posInt] === DG.INT_NULL ? 1 : tableValues[aar][posInt] + 1;
|
|
340
|
-
tableTooltips[aar][posInt] = !tableTooltips[aar][posInt].length ?
|
|
341
|
-
[{key: 'Substitution', value: 'Values'}] : tableTooltips[aar][posInt];
|
|
342
|
-
tableTooltips[aar][posInt].push(subst[posInt][1]);
|
|
343
|
-
tableCases[aar][posInt].push([i, j, subst == subst1 ? delta : -delta]);
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
310
|
+
for (const tempDataElement of tempData) {
|
|
311
|
+
const position = tempDataElement.pos;
|
|
348
312
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
newCol.semType = 'Substitution';
|
|
354
|
-
return newCol;
|
|
355
|
-
});
|
|
356
|
-
const aarCol = DG.Column.string(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, dfLength);
|
|
357
|
-
cols.splice(0, 0, aarCol);
|
|
358
|
-
const table = DG.DataFrame.fromColumns(cols);
|
|
359
|
-
|
|
360
|
-
for (let i = 0; i < dfLength; i++) {
|
|
361
|
-
const aar = tableValuesKeys[i];
|
|
362
|
-
// tableValues[aar].splice(0, 1);
|
|
363
|
-
table.rows.setValues(i, [aar, ...tableValues[aar]]);
|
|
364
|
-
}
|
|
313
|
+
//Working with seq1monomer
|
|
314
|
+
const seq1monomer = tempDataElement.seq1monomer;
|
|
315
|
+
if (!this.substitutionsInfo.has(seq1monomer))
|
|
316
|
+
this.substitutionsInfo.set(seq1monomer, new Map());
|
|
365
317
|
|
|
366
|
-
|
|
318
|
+
let positionsMap = this.substitutionsInfo.get(seq1monomer)!;
|
|
319
|
+
if (!positionsMap.has(position))
|
|
320
|
+
positionsMap.set(position, new Map());
|
|
367
321
|
|
|
368
|
-
|
|
369
|
-
// Object.keys(aarGroups).forEach((value) => groupMapping[value] = value);
|
|
370
|
-
this._substTableTooltipData = tableTooltips;
|
|
371
|
-
this._casesTable = tableCases;
|
|
372
|
-
this.substitutionTable = table;
|
|
322
|
+
let indexes = positionsMap.get(position)!;
|
|
373
323
|
|
|
374
|
-
|
|
375
|
-
|
|
324
|
+
!indexes.has(seq1Idx) ? indexes.set(seq1Idx, [seq2Idx]) : (indexes.get(seq1Idx)! as number[]).push(seq2Idx);
|
|
325
|
+
|
|
326
|
+
//Working with seq2monomer
|
|
327
|
+
const seq2monomer = tempDataElement.seq2monomer;
|
|
328
|
+
if (!this.substitutionsInfo.has(seq2monomer))
|
|
329
|
+
this.substitutionsInfo.set(seq2monomer, new Map());
|
|
330
|
+
|
|
331
|
+
positionsMap = this.substitutionsInfo.get(seq2monomer)!;
|
|
332
|
+
if (!positionsMap.has(position))
|
|
333
|
+
positionsMap.set(position, new Map());
|
|
334
|
+
|
|
335
|
+
indexes = positionsMap.get(position)!;
|
|
336
|
+
!indexes.has(seq2Idx) ? indexes.set(seq2Idx, [seq1Idx]) : (indexes.get(seq2Idx)! as number[]).push(seq1Idx);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
376
340
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
341
|
+
const TypedArray = getTypedArrayConstructor(nRows);
|
|
342
|
+
for (const positionMap of this.substitutionsInfo.values()) {
|
|
343
|
+
for (const indexMap of positionMap.values()) {
|
|
344
|
+
for (const [index, indexArray] of indexMap.entries())
|
|
345
|
+
indexMap.set(index, new TypedArray(indexArray));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
383
348
|
}
|
|
384
349
|
|
|
385
|
-
joinDataFrames(
|
|
350
|
+
joinDataFrames(positionColumns: string[], splitSeqDf: DG.DataFrame): void {
|
|
386
351
|
// append splitSeqDf columns to source table and make sure columns are not added more than once
|
|
387
|
-
const
|
|
352
|
+
const name = this._dataFrame.name;
|
|
353
|
+
const dfColsSet = new Set(this._dataFrame.columns.names());
|
|
388
354
|
if (!positionColumns.every((col: string) => dfColsSet.has(col))) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
positionColumns, 'inner', true);
|
|
355
|
+
this._dataFrame.join(splitSeqDf, [C.COLUMNS_NAMES.ACTIVITY], [C.COLUMNS_NAMES.ACTIVITY],
|
|
356
|
+
this._dataFrame.columns.names(), positionColumns, 'inner', true);
|
|
392
357
|
}
|
|
358
|
+
this._dataFrame.name = name;
|
|
359
|
+
this.currentView.name = name;
|
|
393
360
|
}
|
|
394
361
|
|
|
395
|
-
sortSourceGrid(sourceGrid: DG.Grid) {
|
|
362
|
+
sortSourceGrid(sourceGrid: DG.Grid): void {
|
|
396
363
|
if (sourceGrid) {
|
|
397
364
|
const colNames: DG.GridColumn[] = [];
|
|
398
365
|
for (let i = 1; i < sourceGrid.columns.length; i++)
|
|
@@ -412,54 +379,57 @@ export class PeptidesModel {
|
|
|
412
379
|
}
|
|
413
380
|
}
|
|
414
381
|
|
|
382
|
+
//TODO: move out, merge with controller's scaleActivity
|
|
415
383
|
async createScaledCol(
|
|
416
384
|
activityScaling: string, df: DG.DataFrame, sourceGrid: DG.Grid, splitSeqDf: DG.DataFrame,
|
|
417
|
-
) {
|
|
418
|
-
const [scaledDf, newColName] = await
|
|
419
|
-
activityScaling, df, df.
|
|
385
|
+
): Promise<void> {
|
|
386
|
+
const [scaledDf, newColName] = await PeptidesModel.scaleActivity(
|
|
387
|
+
activityScaling, df, df.tags[C.COLUMNS_NAMES.ACTIVITY]);
|
|
420
388
|
//TODO: make another func
|
|
421
389
|
const scaledCol = scaledDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
422
|
-
|
|
390
|
+
scaledCol.semType = C.SEM_TYPES.ACTIVITY_SCALED;
|
|
391
|
+
splitSeqDf.columns.add(scaledCol);
|
|
423
392
|
const oldScaledCol = df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
424
|
-
|
|
393
|
+
df.columns.replace(oldScaledCol, scaledCol);
|
|
425
394
|
const gridCol = sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
426
395
|
if (gridCol !== null) {
|
|
427
396
|
gridCol.name = newColName;
|
|
428
|
-
df.
|
|
397
|
+
df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newColName;
|
|
429
398
|
}
|
|
430
399
|
|
|
431
400
|
sourceGrid.columns.setOrder([newColName]);
|
|
432
401
|
}
|
|
433
402
|
|
|
434
|
-
|
|
403
|
+
//TODO: move out
|
|
404
|
+
async calculateStatistics(
|
|
405
|
+
matrixDf: DG.DataFrame, peptidesCount: number, splitSeqDf: DG.DataFrame): Promise<DG.DataFrame> {
|
|
435
406
|
matrixDf = matrixDf.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE])
|
|
436
407
|
.add('count', C.COLUMNS_NAMES.ACTIVITY_SCALED, 'Count')
|
|
437
408
|
.aggregate();
|
|
438
409
|
|
|
439
410
|
const countThreshold = 4;
|
|
440
|
-
//@ts-ignore: never gets old
|
|
441
411
|
matrixDf.rows.filter((row) => row.Count >= countThreshold && row.Count <= peptidesCount - countThreshold);
|
|
442
412
|
matrixDf = matrixDf.clone(matrixDf.filter);
|
|
443
413
|
|
|
444
414
|
// calculate additional stats
|
|
445
|
-
await
|
|
415
|
+
await matrixDf.columns.addNewCalculated('Ratio', '${count}/'.concat(`${peptidesCount}`));
|
|
446
416
|
|
|
447
417
|
//calculate p-values based on t-test
|
|
448
418
|
let pvalues: Float32Array = new Float32Array(matrixDf.rowCount).fill(1);
|
|
449
|
-
const mdCol: DG.Column =
|
|
450
|
-
const pValCol: DG.Column =
|
|
419
|
+
const mdCol: DG.Column = matrixDf.columns.addNewFloat(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
420
|
+
const pValCol: DG.Column = matrixDf.columns.addNewFloat(C.COLUMNS_NAMES.P_VALUE);
|
|
421
|
+
const aarCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
422
|
+
const posCol = matrixDf.getCol(C.COLUMNS_NAMES.POSITION);
|
|
451
423
|
for (let i = 0; i < matrixDf.rowCount; i++) {
|
|
452
|
-
const position =
|
|
453
|
-
const aar =
|
|
424
|
+
const position = posCol.get(i);
|
|
425
|
+
const aar = aarCol.get(i);
|
|
454
426
|
|
|
455
|
-
//@ts-ignore
|
|
456
427
|
splitSeqDf.rows.select((row) => row[position] === aar);
|
|
457
428
|
const currentActivity: number[] = splitSeqDf
|
|
458
429
|
.clone(splitSeqDf.selection, [C.COLUMNS_NAMES.ACTIVITY_SCALED])
|
|
459
430
|
.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED)
|
|
460
431
|
.toList();
|
|
461
432
|
|
|
462
|
-
//@ts-ignore
|
|
463
433
|
splitSeqDf.rows.select((row) => row[position] !== aar);
|
|
464
434
|
const otherActivity: number[] = splitSeqDf
|
|
465
435
|
.clone(splitSeqDf.selection, [C.COLUMNS_NAMES.ACTIVITY_SCALED])
|
|
@@ -467,7 +437,6 @@ export class PeptidesModel {
|
|
|
467
437
|
.toList();
|
|
468
438
|
|
|
469
439
|
const testResult = tTest(currentActivity, otherActivity);
|
|
470
|
-
// testResult = uTest(currentActivity, otherActivity);
|
|
471
440
|
const currentMeanDiff = testResult[C.COLUMNS_NAMES.MEAN_DIFFERENCE]!;
|
|
472
441
|
const pvalue = testResult[currentMeanDiff >= 0 ? 'p-value more' : 'p-value less'];
|
|
473
442
|
|
|
@@ -483,25 +452,25 @@ export class PeptidesModel {
|
|
|
483
452
|
return matrixDf.clone();
|
|
484
453
|
}
|
|
485
454
|
|
|
486
|
-
async setCategoryOrder(twoColorMode: boolean, statsDf: DG.DataFrame, matrixDf: DG.DataFrame) {
|
|
455
|
+
async setCategoryOrder(twoColorMode: boolean, statsDf: DG.DataFrame, matrixDf: DG.DataFrame): Promise<void> {
|
|
487
456
|
const absMD = 'Absolute Mean difference';
|
|
488
457
|
const sortArgument = twoColorMode ? absMD : C.COLUMNS_NAMES.MEAN_DIFFERENCE;
|
|
489
458
|
if (twoColorMode)
|
|
490
|
-
await
|
|
459
|
+
await statsDf.columns.addNewCalculated(absMD, 'Abs(${Mean difference})');
|
|
491
460
|
|
|
492
461
|
const aarWeightsDf = statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).sum(sortArgument, 'weight').aggregate();
|
|
493
462
|
const aarList = aarWeightsDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).toList();
|
|
494
|
-
const getWeight = (aar: string) => aarWeightsDf
|
|
463
|
+
const getWeight = (aar: string): number => aarWeightsDf
|
|
495
464
|
.groupBy(['weight'])
|
|
496
465
|
.where(`${C.COLUMNS_NAMES.AMINO_ACID_RESIDUE} = ${aar}`)
|
|
497
466
|
.aggregate()
|
|
498
|
-
.get('weight', 0);
|
|
467
|
+
.get('weight', 0) as number;
|
|
499
468
|
aarList.sort((first, second) => getWeight(second) - getWeight(first));
|
|
500
469
|
|
|
501
470
|
matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).setCategoryOrder(aarList);
|
|
502
471
|
}
|
|
503
472
|
|
|
504
|
-
createVerticalTable(statsDf: DG.DataFrame, twoColorMode: boolean) {
|
|
473
|
+
createVerticalTable(statsDf: DG.DataFrame, twoColorMode: boolean): DG.DataFrame {
|
|
505
474
|
// TODO: aquire ALL of the positions
|
|
506
475
|
const columns = [C.COLUMNS_NAMES.MEAN_DIFFERENCE, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, C.COLUMNS_NAMES.POSITION,
|
|
507
476
|
'Count', 'Ratio', C.COLUMNS_NAMES.P_VALUE];
|
|
@@ -511,47 +480,51 @@ export class PeptidesModel {
|
|
|
511
480
|
|
|
512
481
|
let tempStats: DG.Stats;
|
|
513
482
|
const maxAtPos: {[index: string]: number} = {};
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
483
|
+
const posColCategories = sequenceDf.getCol(C.COLUMNS_NAMES.POSITION).categories;
|
|
484
|
+
const mdCol = sequenceDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
485
|
+
const posCol = sequenceDf.getCol(C.COLUMNS_NAMES.POSITION);
|
|
486
|
+
const rowCount = sequenceDf.rowCount;
|
|
487
|
+
for (const pos of posColCategories) {
|
|
488
|
+
tempStats = DG.Stats.fromColumn(mdCol, DG.BitSet.create(rowCount, (i) => posCol.get(i) === pos));
|
|
519
489
|
maxAtPos[pos] = twoColorMode ?
|
|
520
|
-
(tempStats.max > Math.abs(tempStats.min) ? tempStats.max : tempStats.min) :
|
|
490
|
+
(tempStats.max > Math.abs(tempStats.min) ? tempStats.max : tempStats.min) :
|
|
491
|
+
tempStats.max;
|
|
521
492
|
}
|
|
522
|
-
sequenceDf = sequenceDf.clone(DG.BitSet.create(
|
|
523
|
-
sequenceDf.get(C.COLUMNS_NAMES.MEAN_DIFFERENCE, i) === maxAtPos[sequenceDf.get(C.COLUMNS_NAMES.POSITION, i)]));
|
|
493
|
+
sequenceDf = sequenceDf.clone(DG.BitSet.create(rowCount, (i) => mdCol.get(i) === maxAtPos[posCol.get(i)]));
|
|
524
494
|
|
|
525
495
|
return sequenceDf;
|
|
526
496
|
}
|
|
527
497
|
|
|
528
|
-
createGrids(matrixDf: DG.DataFrame, positionColumns: string[], sequenceDf: DG.DataFrame) {
|
|
498
|
+
createGrids(matrixDf: DG.DataFrame, positionColumns: string[], sequenceDf: DG.DataFrame): DG.Grid[] {
|
|
529
499
|
const sarGrid = matrixDf.plot.grid();
|
|
530
500
|
sarGrid.sort([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]);
|
|
531
501
|
sarGrid.columns.setOrder([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE].concat(positionColumns as C.COLUMNS_NAMES[]));
|
|
532
502
|
|
|
533
503
|
const sarVGrid = sequenceDf.plot.grid();
|
|
534
504
|
sarVGrid.sort([C.COLUMNS_NAMES.POSITION]);
|
|
535
|
-
sarVGrid.col(C.COLUMNS_NAMES.P_VALUE)
|
|
536
|
-
|
|
505
|
+
const pValGridCol = sarVGrid.col(C.COLUMNS_NAMES.P_VALUE)!;
|
|
506
|
+
pValGridCol.format = '#.000';
|
|
507
|
+
pValGridCol.name = 'P-value';
|
|
537
508
|
|
|
538
|
-
let tempCol =
|
|
509
|
+
let tempCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
539
510
|
if (tempCol)
|
|
540
|
-
|
|
511
|
+
setAARRenderer(tempCol, sarGrid);
|
|
541
512
|
|
|
542
|
-
tempCol =
|
|
513
|
+
tempCol = sequenceDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
|
|
543
514
|
if (tempCol)
|
|
544
|
-
|
|
515
|
+
setAARRenderer(tempCol, sarGrid);
|
|
545
516
|
|
|
546
517
|
return [sarGrid, sarVGrid];
|
|
547
518
|
}
|
|
548
519
|
|
|
520
|
+
//TODO: move out
|
|
549
521
|
setCellRenderers(
|
|
550
522
|
renderColNames: string[], statsDf: DG.DataFrame, twoColorMode: boolean, sarGrid: DG.Grid, sarVGrid: DG.Grid,
|
|
551
523
|
isSubstitutionOn: boolean,
|
|
552
|
-
) {
|
|
524
|
+
): void {
|
|
553
525
|
const mdCol = statsDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
554
|
-
|
|
526
|
+
//decompose into two different renering funcs
|
|
527
|
+
const cellRendererAction = (args: DG.GridCellRenderArgs): void => {
|
|
555
528
|
const canvasContext = args.g;
|
|
556
529
|
const bound = args.bounds;
|
|
557
530
|
const cell = args.cell;
|
|
@@ -574,12 +547,10 @@ export class PeptidesModel {
|
|
|
574
547
|
|
|
575
548
|
if (cell.isTableCell && tableColName && tableRowIndex !== null && renderColNames.indexOf(tableColName) !== -1) {
|
|
576
549
|
const gridTable = cell.grid.table;
|
|
577
|
-
const currentPosition = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
|
|
550
|
+
const currentPosition: string = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
|
|
578
551
|
tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
|
|
579
|
-
const currentAAR = gridTable.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
|
|
580
|
-
|
|
581
|
-
console.log('stop');
|
|
582
|
-
|
|
552
|
+
const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
|
|
553
|
+
|
|
583
554
|
const queryAAR = `${C.COLUMNS_NAMES.AMINO_ACID_RESIDUE} = ${currentAAR}`;
|
|
584
555
|
if (cellValue) {
|
|
585
556
|
const query = `${queryAAR} and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
|
|
@@ -601,9 +572,9 @@ export class PeptidesModel {
|
|
|
601
572
|
coef = DG.Color.toHtml(DG.Color.lightLightGray);
|
|
602
573
|
|
|
603
574
|
|
|
604
|
-
const chooseMin = () => twoColorMode ? 0 : mdCol.min;
|
|
605
|
-
const chooseMax = () => twoColorMode ? Math.max(Math.abs(mdCol.min), mdCol.max) : mdCol.max;
|
|
606
|
-
const chooseCurrent = () => twoColorMode ? Math.abs(cellValue) : cellValue;
|
|
575
|
+
const chooseMin = (): number => twoColorMode ? 0 : mdCol.min;
|
|
576
|
+
const chooseMax = (): number => twoColorMode ? Math.max(Math.abs(mdCol.min), mdCol.max) : mdCol.max;
|
|
577
|
+
const chooseCurrent = (): any => twoColorMode ? Math.abs(cellValue) : cellValue;
|
|
607
578
|
|
|
608
579
|
const rCoef = (chooseCurrent() - chooseMin()) / (chooseMax() - chooseMin());
|
|
609
580
|
|
|
@@ -619,15 +590,20 @@ export class PeptidesModel {
|
|
|
619
590
|
if (isSubstitutionOn) {
|
|
620
591
|
canvasContext.textBaseline = 'middle';
|
|
621
592
|
canvasContext.textAlign = 'center';
|
|
622
|
-
canvasContext.fillStyle = DG.Color.toHtml(DG.Color.
|
|
623
|
-
// DG.Color.getContrastColor()
|
|
593
|
+
canvasContext.fillStyle = DG.Color.toHtml(DG.Color.getContrastColor(DG.Color.fromHtml(coef)));
|
|
624
594
|
canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
.
|
|
629
|
-
|
|
630
|
-
|
|
595
|
+
let substValue = 0;
|
|
596
|
+
this.substitutionsInfo.get(currentAAR)?.get(currentPosition)?.forEach((idxs) => substValue += idxs.length);
|
|
597
|
+
if (substValue && substValue != 0)
|
|
598
|
+
canvasContext.fillText(substValue.toString(), midX, midY);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
//TODO: frame based on currentSelection
|
|
602
|
+
const aarSelection = this.currentSelection[currentPosition];
|
|
603
|
+
if (aarSelection && aarSelection.includes(currentAAR)) {
|
|
604
|
+
canvasContext.strokeStyle = '#000';
|
|
605
|
+
canvasContext.lineWidth = 1;
|
|
606
|
+
canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
|
|
631
607
|
}
|
|
632
608
|
}
|
|
633
609
|
args.preventDefault();
|
|
@@ -638,17 +614,18 @@ export class PeptidesModel {
|
|
|
638
614
|
sarVGrid.onCellRender.subscribe(cellRendererAction);
|
|
639
615
|
}
|
|
640
616
|
|
|
617
|
+
//FIXME: doesn't work at all
|
|
641
618
|
setTooltips(
|
|
642
619
|
renderColNames: string[], statsDf: DG.DataFrame, peptidesCount: number, sarGrid: DG.Grid, sarVGrid: DG.Grid,
|
|
643
620
|
sourceDf: DG.DataFrame,
|
|
644
|
-
) {
|
|
645
|
-
const onCellTooltipAction = async (cell: DG.GridCell, x: number, y: number) => {
|
|
621
|
+
): void {
|
|
622
|
+
const onCellTooltipAction = async (cell: DG.GridCell, x: number, y: number): Promise<boolean> => {
|
|
646
623
|
if (
|
|
647
624
|
!cell.isRowHeader && !cell.isColHeader && cell.tableColumn !== null && cell.cell.value !== null &&
|
|
648
625
|
cell.tableRowIndex !== null && renderColNames.indexOf(cell.tableColumn.name) !== -1) {
|
|
649
626
|
const tooltipMap: { [index: string]: string } = {};
|
|
650
627
|
|
|
651
|
-
for (const col of
|
|
628
|
+
for (const col of statsDf.columns.names()) {
|
|
652
629
|
if (col !== C.COLUMNS_NAMES.AMINO_ACID_RESIDUE && col !== C.COLUMNS_NAMES.POSITION) {
|
|
653
630
|
const currentPosition = cell.tableColumn.name !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
|
|
654
631
|
cell.tableColumn.name : cell.grid.table.get(C.COLUMNS_NAMES.POSITION, cell.tableRowIndex);
|
|
@@ -672,11 +649,6 @@ export class PeptidesModel {
|
|
|
672
649
|
ui.tooltip.show(ui.tableFromMap(tooltipMap), x, y);
|
|
673
650
|
}
|
|
674
651
|
if (!cell.isColHeader && cell.tableColumn?.name == C.COLUMNS_NAMES.AMINO_ACID_RESIDUE) {
|
|
675
|
-
// if (grouping) {
|
|
676
|
-
// const currentGroup = C.groupDescription[cell.cell.value];
|
|
677
|
-
// const divText = ui.divText('Amino Acids in this group: ' + currentGroup[C.SEM_TYPES.AMINO_ACIDS].join(', '));
|
|
678
|
-
// ui.tooltip.show(ui.divV([ui.h3(currentGroup['description']), divText]), x, y);
|
|
679
|
-
// } else {
|
|
680
652
|
const monomerLib = sourceDf.temp[MonomerLibrary.id];
|
|
681
653
|
ChemPalette.showTooltip(cell, x, y, monomerLib);
|
|
682
654
|
}
|
|
@@ -686,53 +658,71 @@ export class PeptidesModel {
|
|
|
686
658
|
sarVGrid.onCellTooltip(onCellTooltipAction);
|
|
687
659
|
}
|
|
688
660
|
|
|
689
|
-
|
|
661
|
+
//TODO: think about it, move out?
|
|
662
|
+
setInteractionCallback(): void {
|
|
690
663
|
const sarDf = this._sarGrid.dataFrame;
|
|
691
664
|
const sarVDf = this._sarVGrid.dataFrame;
|
|
692
665
|
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
let position: string;
|
|
696
|
-
if (isVertical) {
|
|
697
|
-
const currentRowIdx = sarVDf.currentRowIdx;
|
|
698
|
-
aar = sarVDf.get(C.COLUMNS_NAMES.MEAN_DIFFERENCE, currentRowIdx);
|
|
699
|
-
position = sarVDf.get(C.COLUMNS_NAMES.POSITION, currentRowIdx);
|
|
700
|
-
} else {
|
|
701
|
-
aar = sarDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, sarDf.currentRowIdx);
|
|
702
|
-
position = sarDf.currentCol.name;
|
|
703
|
-
}
|
|
704
|
-
return [aar, position];
|
|
666
|
+
const chooseAction = (aar: string, position: string, isShiftPressed: boolean) => {
|
|
667
|
+
isShiftPressed ? this.modifyCurrentSelection(aar, position) : this.initCurrentSelection(aar, position);
|
|
705
668
|
};
|
|
706
669
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
670
|
+
const gridCellValidation = (gc: DG.GridCell | null) => !gc || !gc.cell.value || !gc.tableColumn ||
|
|
671
|
+
gc.tableRowIndex == null || gc.tableRowIndex == -1;
|
|
672
|
+
this._sarGrid.root.addEventListener('click', (ev) => {
|
|
673
|
+
const gridCell = this._sarGrid.hitTest(ev.offsetX, ev.offsetY);
|
|
674
|
+
if (gridCellValidation(gridCell) || gridCell!.tableColumn!.name == C.COLUMNS_NAMES.AMINO_ACID_RESIDUE)
|
|
710
675
|
return;
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
[aar, position] = getAARandPosition();
|
|
716
|
-
this.dataFrame.tags[C.TAGS.AAR] = aar;
|
|
717
|
-
this.dataFrame.tags[C.TAGS.POSITION] = position;
|
|
718
|
-
} else {
|
|
719
|
-
this.dataFrame.tags[C.TAGS.AAR] = this.dataFrame.tags[C.TAGS.POSITION] = null;
|
|
720
|
-
}
|
|
721
|
-
this.dataFrame.temp['substTable'] = this.getSubstitutionTable();
|
|
722
|
-
this.modifyOrCreateSplitCol(aar, position);
|
|
723
|
-
this.fireBitsetChanged();
|
|
724
|
-
this.invalidateGrids();
|
|
725
|
-
grok.shell.o = this.dataFrame;
|
|
676
|
+
|
|
677
|
+
const position = gridCell!.tableColumn!.name;
|
|
678
|
+
const aar = sarDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, gridCell!.tableRowIndex!);
|
|
679
|
+
chooseAction(aar, position, ev.shiftKey);
|
|
726
680
|
});
|
|
727
681
|
|
|
728
|
-
this._sarVGrid.
|
|
729
|
-
|
|
682
|
+
this._sarVGrid.root.addEventListener('click', (ev) => {
|
|
683
|
+
const gridCell = this._sarVGrid.hitTest(ev.offsetX, ev.offsetY);
|
|
684
|
+
if (gridCellValidation(gridCell) || gridCell!.tableColumn!.name != C.COLUMNS_NAMES.MEAN_DIFFERENCE)
|
|
730
685
|
return;
|
|
731
|
-
|
|
686
|
+
|
|
687
|
+
const tableRowIdx = gridCell!.tableRowIndex!;
|
|
688
|
+
const position = sarVDf.get(C.COLUMNS_NAMES.POSITION, tableRowIdx);
|
|
689
|
+
const aar = sarVDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIdx);
|
|
690
|
+
chooseAction(aar, position, ev.shiftKey);
|
|
732
691
|
});
|
|
692
|
+
|
|
693
|
+
const cellChanged = (table: DG.DataFrame) => {
|
|
694
|
+
if (this.isCellChanging)
|
|
695
|
+
return;
|
|
696
|
+
this.isCellChanging = true;
|
|
697
|
+
table.currentRowIdx = -1;
|
|
698
|
+
this.isCellChanging = false;
|
|
699
|
+
};
|
|
700
|
+
this._sarGrid.onCurrentCellChanged.subscribe((_gc) => cellChanged(sarDf));
|
|
701
|
+
this._sarVGrid.onCurrentCellChanged.subscribe((_gc) => cellChanged(sarVDf));
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
modifyCurrentSelection(aar: string, position: string): void {
|
|
705
|
+
const tempSelection = this.currentSelection;
|
|
706
|
+
if (!tempSelection.hasOwnProperty(position))
|
|
707
|
+
tempSelection[position] = [aar];
|
|
708
|
+
else {
|
|
709
|
+
const tempSelectionAt = tempSelection[position];
|
|
710
|
+
const aarIndex = tempSelectionAt.indexOf(aar);
|
|
711
|
+
aarIndex == -1 ? tempSelectionAt.push(aar) :
|
|
712
|
+
tempSelectionAt.length == 1 ? delete tempSelection[position] :
|
|
713
|
+
tempSelectionAt.splice(aarIndex, 1);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
this.currentSelection = tempSelection;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
initCurrentSelection(aar: string, position: string): void {
|
|
720
|
+
const tempSelection: type.SelectionObject = {};
|
|
721
|
+
tempSelection[position] = [aar];
|
|
722
|
+
this.currentSelection = tempSelection;
|
|
733
723
|
}
|
|
734
724
|
|
|
735
|
-
invalidateGrids() {
|
|
725
|
+
invalidateGrids(): void {
|
|
736
726
|
this.stackedBarchart?.computeData();
|
|
737
727
|
this._sarGrid.invalidate();
|
|
738
728
|
this._sarVGrid.invalidate();
|
|
@@ -740,22 +730,53 @@ export class PeptidesModel {
|
|
|
740
730
|
//TODO: this.peptideSpaceGrid.invalidate();
|
|
741
731
|
}
|
|
742
732
|
|
|
743
|
-
setBitsetCallback() {
|
|
733
|
+
setBitsetCallback(): void {
|
|
744
734
|
if (this.isBitsetChangedInitialized)
|
|
745
735
|
return;
|
|
746
|
-
const filter = this.
|
|
747
|
-
const selection = this.
|
|
736
|
+
const filter = this._dataFrame.filter;
|
|
737
|
+
const selection = this._dataFrame.selection;
|
|
748
738
|
|
|
749
|
-
const changeBitset = (currentBitset: DG.BitSet, previousBitset: DG.BitSet) => {
|
|
739
|
+
const changeBitset = (currentBitset: DG.BitSet, previousBitset: DG.BitSet): void => {
|
|
750
740
|
previousBitset.setAll(!this._filterMode, false);
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
741
|
+
|
|
742
|
+
const edfSelection = this.edf?.selection;
|
|
743
|
+
if (this.isPeptideSpaceChangingBitset) {
|
|
744
|
+
if (edfSelection == null)
|
|
745
|
+
return;
|
|
746
|
+
|
|
747
|
+
currentBitset.init((i) => edfSelection.get(i) ?? false, false);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const updateEdfSelection = () => {
|
|
752
|
+
this.isChangingEdfBitset = true;
|
|
753
|
+
edfSelection?.copyFrom(currentBitset);
|
|
754
|
+
this.isChangingEdfBitset = false;
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
const positionList = Object.keys(this.currentSelection);
|
|
758
|
+
if (positionList.length == 0) {
|
|
759
|
+
currentBitset.init(() => false, false);
|
|
760
|
+
updateEdfSelection();
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
//TODO: move out
|
|
765
|
+
const getBitAt = (i: number) => {
|
|
766
|
+
for (const position of positionList) {
|
|
767
|
+
const positionCol: DG.Column<string> = this._dataFrame.getCol(position);
|
|
768
|
+
if (this._currentSelection[position].includes(positionCol.get(i)))
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
return false;
|
|
772
|
+
};
|
|
773
|
+
currentBitset.init(getBitAt, false);
|
|
774
|
+
|
|
775
|
+
updateEdfSelection();
|
|
755
776
|
};
|
|
756
777
|
|
|
757
778
|
const recalculateStatistics =
|
|
758
|
-
(bitset: DG.BitSet) => (this.
|
|
779
|
+
(bitset: DG.BitSet): void => (this._dataFrame.temp[C.STATS] as FilteringStatistics).setMask(bitset);
|
|
759
780
|
|
|
760
781
|
filter.onChanged.subscribe(() => {
|
|
761
782
|
changeBitset(filter, selection);
|
|
@@ -768,9 +789,18 @@ export class PeptidesModel {
|
|
|
768
789
|
this.isBitsetChangedInitialized = true;
|
|
769
790
|
}
|
|
770
791
|
|
|
771
|
-
fireBitsetChanged(
|
|
792
|
+
fireBitsetChanged(isPeptideSpaceSource: boolean = false): void {
|
|
793
|
+
this.isPeptideSpaceChangingBitset = isPeptideSpaceSource;
|
|
794
|
+
this.getBiteset().fireChanged();
|
|
795
|
+
this.isPeptideSpaceChangingBitset = false;
|
|
796
|
+
this.modifyOrCreateSplitCol();
|
|
797
|
+
grok.shell.o = this.createAccordion().root;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
getBiteset(): DG.BitSet {return this._filterMode ? this._dataFrame.filter : this._dataFrame.selection;}
|
|
772
801
|
|
|
773
|
-
|
|
802
|
+
//TODO: move out
|
|
803
|
+
postProcessGrids(sourceGrid: DG.Grid, invalidIndexes: number[], sarGrid: DG.Grid, sarVGrid: DG.Grid): void {
|
|
774
804
|
sourceGrid.onCellPrepare((cell: DG.GridCell) => {
|
|
775
805
|
const currentRowIndex = cell.tableRowIndex;
|
|
776
806
|
if (currentRowIndex && invalidIndexes.includes(currentRowIndex) && !cell.isRowHeader)
|
|
@@ -781,27 +811,77 @@ export class PeptidesModel {
|
|
|
781
811
|
mdCol.name = 'Diff';
|
|
782
812
|
|
|
783
813
|
for (const grid of [sarGrid, sarVGrid]) {
|
|
784
|
-
grid.props
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
814
|
+
const gridProps = grid.props;
|
|
815
|
+
gridProps.rowHeight = 20;
|
|
816
|
+
const girdCols = grid.columns;
|
|
817
|
+
const colNum = girdCols.length;
|
|
818
|
+
for (let i = 0; i < colNum; ++i) {
|
|
819
|
+
const col = girdCols.byIndex(i)!;
|
|
820
|
+
const colName = col.name;
|
|
821
|
+
if (grid == sarVGrid && colName !== 'Diff' && colName !== C.COLUMNS_NAMES.AMINO_ACID_RESIDUE)
|
|
822
|
+
col.width = 50;
|
|
790
823
|
else
|
|
791
|
-
col.width =
|
|
824
|
+
col.width = gridProps.rowHeight + 10;
|
|
792
825
|
}
|
|
793
826
|
}
|
|
794
827
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
828
|
+
const setViewerGridProps = (grid: DG.Grid) => {
|
|
829
|
+
grid.props.allowEdit = false;
|
|
830
|
+
grid.props.allowRowSelection = false;
|
|
831
|
+
grid.props.allowBlockSelection = false;
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
setViewerGridProps(sarGrid);
|
|
835
|
+
setViewerGridProps(sarVGrid);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
getSplitColValueAt(index: number, aar: string, position: string, aarLabel: string): string {
|
|
839
|
+
const currentAAR = this._dataFrame.get(position, index) as string;
|
|
840
|
+
return currentAAR === aar ? aarLabel : C.CATEGORIES.OTHER;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
modifyOrCreateSplitCol(): void {
|
|
844
|
+
const bs = this.getBiteset();
|
|
845
|
+
this.splitCol = this._dataFrame.col(C.COLUMNS_NAMES.SPLIT_COL) ??
|
|
846
|
+
this._dataFrame.columns.addNewBool(C.COLUMNS_NAMES.SPLIT_COL);
|
|
847
|
+
this.splitCol.init((i) => bs.get(i));
|
|
848
|
+
this.splitCol.compact();
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
static async scaleActivity(
|
|
852
|
+
activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
|
|
853
|
+
): Promise<[DG.DataFrame, string]> {
|
|
854
|
+
let currentActivityColName = originalActivityName ?? C.COLUMNS_NAMES.ACTIVITY;
|
|
855
|
+
const flag = df.columns.names().includes(currentActivityColName) &&
|
|
856
|
+
currentActivityColName === originalActivityName;
|
|
857
|
+
currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
|
|
858
|
+
const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
|
|
859
|
+
|
|
860
|
+
let formula = '${' + currentActivityColName + '}';
|
|
861
|
+
let newColName = 'activity';
|
|
862
|
+
switch (activityScaling) {
|
|
863
|
+
case 'none':
|
|
864
|
+
break;
|
|
865
|
+
case 'lg':
|
|
866
|
+
formula = `Log10(${formula})`;
|
|
867
|
+
newColName = `Log10(${newColName})`;
|
|
868
|
+
break;
|
|
869
|
+
case '-lg':
|
|
870
|
+
formula = `-1*Log10(${formula})`;
|
|
871
|
+
newColName = `-Log10(${newColName})`;
|
|
872
|
+
break;
|
|
873
|
+
default:
|
|
874
|
+
throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
await tempDf.columns.addNewCalculated(C.COLUMNS_NAMES.ACTIVITY_SCALED, formula);
|
|
878
|
+
df.tags['scaling'] = activityScaling;
|
|
799
879
|
|
|
800
|
-
|
|
801
|
-
sarVGrid.props.allowEdit = false;
|
|
880
|
+
return [tempDf, newColName];
|
|
802
881
|
}
|
|
803
882
|
|
|
804
|
-
|
|
883
|
+
static splitAlignedPeptides(peptideColumn: DG.Column<string>, filter: boolean = true): [DG.DataFrame, number[]] {
|
|
884
|
+
const separator = peptideColumn.tags[C.TAGS.SEPARATOR] ?? getSeparator(peptideColumn);
|
|
805
885
|
const splitPeptidesArray: string[][] = [];
|
|
806
886
|
let currentSplitPeptide: string[];
|
|
807
887
|
let modeMonomerCount = 0;
|
|
@@ -809,16 +889,16 @@ export class PeptidesModel {
|
|
|
809
889
|
const colLength = peptideColumn.length;
|
|
810
890
|
|
|
811
891
|
// splitting data
|
|
812
|
-
const monomerLengths: {
|
|
892
|
+
const monomerLengths: {[index: string]: number} = {};
|
|
813
893
|
for (let i = 0; i < colLength; i++) {
|
|
814
|
-
currentSplitPeptide = peptideColumn.get(i).split(
|
|
894
|
+
currentSplitPeptide = peptideColumn.get(i).split(separator).map((value: string) => value ? value : '-');
|
|
815
895
|
splitPeptidesArray.push(currentSplitPeptide);
|
|
816
896
|
currentLength = currentSplitPeptide.length;
|
|
817
897
|
monomerLengths[currentLength + ''] =
|
|
818
898
|
monomerLengths[currentLength + ''] ? monomerLengths[currentLength + ''] + 1 : 1;
|
|
819
899
|
}
|
|
820
|
-
|
|
821
|
-
|
|
900
|
+
modeMonomerCount =
|
|
901
|
+
parseInt(Object.keys(monomerLengths).reduce((a, b) => monomerLengths[a] > monomerLengths[b] ? a : b));
|
|
822
902
|
|
|
823
903
|
// making sure all of the sequences are of the same size
|
|
824
904
|
// and marking invalid sequences
|
|
@@ -841,9 +921,9 @@ export class PeptidesModel {
|
|
|
841
921
|
modeMonomerCount--; // minus C-terminal
|
|
842
922
|
|
|
843
923
|
//create column names list
|
|
844
|
-
const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1}`);
|
|
845
|
-
columnNames.splice(0, 0, 'N
|
|
846
|
-
columnNames.push('C
|
|
924
|
+
const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1 }`);
|
|
925
|
+
columnNames.splice(0, 0, 'N');
|
|
926
|
+
columnNames.push('C');
|
|
847
927
|
|
|
848
928
|
// filter out the columns with the same values
|
|
849
929
|
if (filter) {
|
|
@@ -856,134 +936,110 @@ export class PeptidesModel {
|
|
|
856
936
|
});
|
|
857
937
|
}
|
|
858
938
|
|
|
859
|
-
return
|
|
939
|
+
return [
|
|
940
|
+
DG.DataFrame.fromColumns(splitColumns.map((positionArray, index) => {
|
|
941
|
+
return DG.Column.fromList('string', columnNames[index], positionArray);
|
|
942
|
+
})),
|
|
943
|
+
invalidIndexes,
|
|
944
|
+
];
|
|
860
945
|
}
|
|
861
946
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
tempDf.rows.setValues(i, [col.get(row[0]), col.get(row[1]), row[2]]);
|
|
894
|
-
}
|
|
947
|
+
syncProperties(isSourceSAR = true): void {
|
|
948
|
+
const sarViewer: SARViewer = this._dataFrame.temp['sarViewer'];
|
|
949
|
+
const sarViewerVertical: SARViewerVertical = this._dataFrame.temp['sarViewerVertical'];
|
|
950
|
+
const sourceViewer = isSourceSAR ? sarViewer : sarViewerVertical;
|
|
951
|
+
const targetViewer = isSourceSAR ? sarViewerVertical : sarViewer;
|
|
952
|
+
const properties = sourceViewer.props.getProperties();
|
|
953
|
+
for (const property of properties)
|
|
954
|
+
targetViewer.props.set(property.name, property.get(sourceViewer));
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/** Class initializer */
|
|
958
|
+
async init(): Promise<void> {
|
|
959
|
+
if (this.isInitialized)
|
|
960
|
+
return;
|
|
961
|
+
this.isInitialized = true;
|
|
962
|
+
//calculate initial stats
|
|
963
|
+
const stats = new FilteringStatistics();
|
|
964
|
+
const activityScaledCol = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
965
|
+
stats.setData(activityScaledCol.getRawData() as Float32Array);
|
|
966
|
+
stats.setMask(this._dataFrame.selection);
|
|
967
|
+
this._dataFrame.temp[C.STATS] = stats;
|
|
968
|
+
|
|
969
|
+
this.currentView = this._dataFrame.tags[C.PEPTIDES_ANALYSIS] == 'true' ? grok.shell.v as DG.TableView :
|
|
970
|
+
grok.shell.addTableView(this._dataFrame);
|
|
971
|
+
const sourceGrid = this.currentView.grid;
|
|
972
|
+
if (this._dataFrame.tags[C.PEPTIDES_ANALYSIS] == 'true')
|
|
973
|
+
return;
|
|
974
|
+
|
|
975
|
+
this._dataFrame.tags[C.PEPTIDES_ANALYSIS] = 'true';
|
|
976
|
+
sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!.name = this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED];
|
|
977
|
+
sourceGrid.columns.setOrder([this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED]]);
|
|
895
978
|
|
|
896
|
-
// tempDf.temp['isReal'] = true;
|
|
897
979
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
980
|
+
this._dataFrame.temp[C.EMBEDDING_STATUS] = false;
|
|
981
|
+
const adjustCellSize = (grid: DG.Grid): void => {
|
|
982
|
+
const colNum = grid.columns.length;
|
|
983
|
+
for (let i = 0; i < colNum; ++i) {
|
|
984
|
+
const iCol = grid.columns.byIndex(i)!;
|
|
985
|
+
iCol.width = isNaN(parseInt(iCol.name)) ? 50 : 40;
|
|
986
|
+
}
|
|
987
|
+
grid.props.rowHeight = 20;
|
|
988
|
+
};
|
|
902
989
|
|
|
903
|
-
|
|
904
|
-
|
|
990
|
+
for (let i = 0; i < sourceGrid.columns.length; i++) {
|
|
991
|
+
const aarCol = sourceGrid.columns.byIndex(i);
|
|
992
|
+
if (aarCol && aarCol.name && aarCol.column?.semType !== C.SEM_TYPES.AMINO_ACIDS &&
|
|
993
|
+
aarCol.name !== this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED])
|
|
994
|
+
aarCol.visible = false;
|
|
905
995
|
}
|
|
906
|
-
return null;
|
|
907
|
-
}
|
|
908
996
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
let otherColName: string;
|
|
912
|
-
let otherRowIndex: number;
|
|
913
|
-
const otherDf = sourceVertical ? sarDf : sarVDf;
|
|
997
|
+
const options = {scaling: this._dataFrame.tags['scaling']};
|
|
998
|
+
await this.updateData(this._dataFrame.tags['scaling'], sourceGrid, false, 1, 2, false, false);
|
|
914
999
|
|
|
915
|
-
|
|
916
|
-
return;
|
|
1000
|
+
const dockManager = this.currentView.dockManager;
|
|
917
1001
|
|
|
918
|
-
|
|
919
|
-
if (sourceVertical) {
|
|
920
|
-
const currentRowIdx = sarVDf.currentRowIdx;
|
|
921
|
-
const currentColName = sarVDf.currentCol.name;
|
|
922
|
-
if (currentColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE)
|
|
923
|
-
return;
|
|
1002
|
+
const sarViewer = await this._dataFrame.plot.fromType('peptide-sar-viewer', options) as SARViewer;
|
|
924
1003
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
otherRowIndex = -1;
|
|
928
|
-
const rows = otherDf.rowCount;
|
|
929
|
-
for (let i = 0; i < rows; i++) {
|
|
930
|
-
if (otherDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, i) === otherRowName) {
|
|
931
|
-
otherRowIndex = i;
|
|
932
|
-
break;
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
//on SAR viewer click
|
|
936
|
-
} else {
|
|
937
|
-
otherColName = C.COLUMNS_NAMES.MEAN_DIFFERENCE;
|
|
938
|
-
const otherPos: string = sarDf.currentCol.name;
|
|
939
|
-
if (otherPos === C.COLUMNS_NAMES.AMINO_ACID_RESIDUE)
|
|
940
|
-
return;
|
|
1004
|
+
const sarViewerVertical =
|
|
1005
|
+
await this._dataFrame.plot.fromType('peptide-sar-viewer-vertical', options) as SARViewerVertical;
|
|
941
1006
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
) {
|
|
950
|
-
otherRowIndex = i;
|
|
951
|
-
break;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
1007
|
+
const sarViewersGroup: viewerTypes[] = [sarViewer, sarViewerVertical];
|
|
1008
|
+
|
|
1009
|
+
if (this._dataFrame.rowCount <= 10000) {
|
|
1010
|
+
const peptideSpaceViewerOptions = {method: 'UMAP', measure: 'Levenshtein', cyclesCount: 100};
|
|
1011
|
+
const peptideSpaceViewer =
|
|
1012
|
+
await this._dataFrame.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
|
|
1013
|
+
dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space Viewer');
|
|
954
1014
|
}
|
|
955
|
-
otherDf.temp[C.FLAGS.CELL_CHANGING] = true;
|
|
956
|
-
otherDf.currentCell = otherDf.cell(otherRowIndex, otherColName);
|
|
957
|
-
otherDf.temp[C.FLAGS.CELL_CHANGING] = false;
|
|
958
|
-
}
|
|
959
1015
|
|
|
960
|
-
|
|
961
|
-
const currentAAR = this.dataFrame.get(position, index) as string;
|
|
962
|
-
return currentAAR === aar ? aarLabel : C.CATEGORIES.OTHER;
|
|
963
|
-
}
|
|
1016
|
+
dockViewers(sarViewersGroup, DG.DOCK_TYPE.RIGHT, dockManager, DG.DOCK_TYPE.DOWN);
|
|
964
1017
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
this.splitCol = df.col(C.COLUMNS_NAMES.SPLIT_COL) ??
|
|
968
|
-
df.columns.addNew(C.COLUMNS_NAMES.SPLIT_COL, 'string') as DG.Column;
|
|
1018
|
+
sourceGrid.props.allowEdit = false;
|
|
1019
|
+
adjustCellSize(sourceGrid);
|
|
969
1020
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
1021
|
+
this.invalidateGrids();
|
|
1022
|
+
}
|
|
974
1023
|
|
|
975
|
-
|
|
976
|
-
|
|
1024
|
+
invalidateSourceGrid(): void {this._sourceGrid.invalidate();}
|
|
1025
|
+
}
|
|
977
1026
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1027
|
+
type viewerTypes = SARViewer | SARViewerVertical;
|
|
1028
|
+
|
|
1029
|
+
function dockViewers(
|
|
1030
|
+
viewerList: viewerTypes[], attachDirection: DG.DockType, dockManager: DG.DockManager,
|
|
1031
|
+
initialAttachDirection?: DG.DockType): DG.DockNode[] | null {
|
|
1032
|
+
const viewerListLength = viewerList.length;
|
|
1033
|
+
if (viewerListLength === 0)
|
|
1034
|
+
return null;
|
|
981
1035
|
|
|
982
|
-
|
|
1036
|
+
let currentViewer = viewerList[0];
|
|
1037
|
+
const nodeList = [dockManager.dock(currentViewer, initialAttachDirection, null, currentViewer.name ?? '')];
|
|
1038
|
+
const ratio = 1 / viewerListLength;
|
|
983
1039
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
df.getCol(C.COLUMNS_NAMES.SPLIT_COL).colors.setCategorical(colorMap);
|
|
1040
|
+
for (let i = 1; i < viewerListLength; i++) {
|
|
1041
|
+
currentViewer = viewerList[i];
|
|
1042
|
+
nodeList.push(dockManager.dock(currentViewer, attachDirection, nodeList[i - 1], currentViewer.name ?? '', ratio));
|
|
988
1043
|
}
|
|
1044
|
+
return nodeList;
|
|
989
1045
|
}
|