@datagrok/peptides 0.8.8 → 0.8.9
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/package.json +10 -10
- package/src/describe.ts +96 -97
- package/src/model.ts +96 -75
- package/src/monomer-library.ts +10 -12
- package/src/package-test.ts +3 -3
- package/src/package.ts +39 -59
- package/src/peptides.ts +218 -108
- package/src/tests/peptide-space-test.ts +1 -1
- package/src/tests/peptides-tests.ts +6 -6
- package/src/tests/utils.ts +3 -2
- package/src/utils/cell-renderer.ts +89 -61
- package/src/utils/chem-palette.ts +66 -32
- package/src/utils/peptide-similarity-space.ts +18 -28
- package/src/utils/split-aligned.ts +55 -55
- package/src/viewers/logo-viewer.ts +5 -4
- package/src/viewers/sar-viewer.ts +88 -110
- package/src/viewers/stacked-barchart-viewer.ts +359 -359
- package/src/viewers/subst-viewer.ts +108 -73
- package/src/widgets/analyze-peptides.ts +26 -26
- package/src/widgets/manual-alignment.ts +7 -4
- package/src/widgets/multiple-sequence-alignment.ts +9 -0
- package/src/widgets/peptide-molecule.ts +5 -3
- package/src/widgets/subst-table.ts +65 -0
- package/src/workers/dimensionality-reducer.ts +1 -1
|
@@ -4,8 +4,9 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import $ from 'cash-dom';
|
|
5
5
|
|
|
6
6
|
import * as logojs from 'logojs-react';
|
|
7
|
-
import {splitAlignedPeptides} from '../utils/split-aligned';
|
|
7
|
+
// import {splitAlignedPeptides} from '../utils/split-aligned';
|
|
8
8
|
import {ChemPalette} from '../utils/chem-palette';
|
|
9
|
+
import {PeptidesController} from '../peptides';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Logo viewer.
|
|
@@ -80,7 +81,7 @@ export class Logo extends DG.JsViewer {
|
|
|
80
81
|
this.initialized = true;
|
|
81
82
|
console.log('INIT');
|
|
82
83
|
this.target = this.dataFrame;
|
|
83
|
-
[this.splitted] = splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
|
|
84
|
+
[this.splitted] = PeptidesController.splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
|
|
84
85
|
this.root.style.width = 'auto';
|
|
85
86
|
this.root.style.height = 'auto';
|
|
86
87
|
this.root.style.maxHeight = '200px';
|
|
@@ -142,8 +143,8 @@ export class Logo extends DG.JsViewer {
|
|
|
142
143
|
.aggregate();
|
|
143
144
|
}
|
|
144
145
|
if (selected)
|
|
145
|
-
[this.splitted] = splitAlignedPeptides(this.target!.columns.bySemType(this.colSemType));
|
|
146
|
-
else [this.splitted] = splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
|
|
146
|
+
[this.splitted] = PeptidesController.splitAlignedPeptides(this.target!.columns.bySemType(this.colSemType));
|
|
147
|
+
else [this.splitted] = PeptidesController.splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
|
|
147
148
|
$(this.root).empty();
|
|
148
149
|
|
|
149
150
|
if (typeof this.dataFrame !== 'undefined')
|
|
@@ -4,8 +4,8 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
7
|
-
|
|
8
|
-
import {
|
|
7
|
+
import {PeptidesController} from '../peptides';
|
|
8
|
+
// import {PeptidesModel} from '../model';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Structure-activity relationship viewer.
|
|
@@ -28,8 +28,11 @@ export class SARViewer extends DG.JsViewer {
|
|
|
28
28
|
protected _initialBitset: DG.BitSet | null;
|
|
29
29
|
protected viewerVGrid: DG.Grid | null;
|
|
30
30
|
protected currentBitset: DG.BitSet | null;
|
|
31
|
-
grouping: boolean;
|
|
32
|
-
groupMapping: StringDictionary | null;
|
|
31
|
+
protected grouping: boolean;
|
|
32
|
+
protected groupMapping: StringDictionary | null;
|
|
33
|
+
// model: PeptidesModel | null;
|
|
34
|
+
protected _name: string = 'Monomer-Positions';
|
|
35
|
+
protected controller: PeptidesController | null;
|
|
33
36
|
// protected pValueThreshold: number;
|
|
34
37
|
// protected amountOfBestAARs: number;
|
|
35
38
|
// duplicatesHandingMethod: string;
|
|
@@ -51,6 +54,8 @@ export class SARViewer extends DG.JsViewer {
|
|
|
51
54
|
this._initialBitset = null;
|
|
52
55
|
this.viewGridInitialized = false;
|
|
53
56
|
this.currentBitset = null;
|
|
57
|
+
// this.model = null;
|
|
58
|
+
this.controller = null;
|
|
54
59
|
|
|
55
60
|
//TODO: find a way to restrict activityColumnName to accept only numerical columns (double even better)
|
|
56
61
|
this.activityColumnName = this.string('activityColumnName');
|
|
@@ -58,47 +63,38 @@ export class SARViewer extends DG.JsViewer {
|
|
|
58
63
|
this.filterMode = this.bool('filterMode', false);
|
|
59
64
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
60
65
|
this.grouping = this.bool('grouping', false);
|
|
61
|
-
// this.pValueThreshold = this.float('pValueThreshold', 0.1);
|
|
62
|
-
// this.amountOfBestAARs = this.int('amountOfBestAAR', 1);
|
|
63
|
-
// this.duplicatesHandingMethod = this.string('duplicatesHandlingMethod', 'median', {choices: ['median']});
|
|
64
66
|
|
|
65
67
|
this.sourceGrid = null;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*/
|
|
70
|
+
get name() {
|
|
71
|
+
return this._name;
|
|
72
|
+
}
|
|
73
|
+
|
|
73
74
|
init() {
|
|
74
75
|
this._initialBitset = this.dataFrame!.filter.clone();
|
|
75
76
|
this.currentBitset = this._initialBitset.clone();
|
|
76
77
|
this.initialized = true;
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async onTableAttached() {
|
|
81
|
+
this.sourceGrid = this.view?.grid ?? (grok.shell.v as DG.TableView).grid;
|
|
82
|
+
this.dataFrame?.setTag('dataType', 'peptides');
|
|
83
|
+
this.controller = PeptidesController.getInstance(this.dataFrame!);
|
|
84
|
+
// this.model = PeptidesModel.getOrInit(this.dataFrame!);
|
|
85
|
+
// this.model = this.controller.getOrInitModel();
|
|
86
|
+
|
|
87
|
+
this.subs.push(this.controller.onStatsDataFrameChanged.subscribe((data) => this.statsDf = data));
|
|
88
|
+
this.subs.push(this.controller.onSARGridChanged.subscribe((data) => {
|
|
79
89
|
this.viewerGrid = data;
|
|
80
|
-
this.render();
|
|
90
|
+
this.render(false);
|
|
81
91
|
}));
|
|
82
|
-
this.subs.push(
|
|
83
|
-
this.subs.push(
|
|
84
|
-
}
|
|
92
|
+
this.subs.push(this.controller.onSARVGridChanged.subscribe((data) => this.viewerVGrid = data));
|
|
93
|
+
this.subs.push(this.controller.onGroupMappingChanged.subscribe((data) => this.groupMapping = data));
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
* Function that is executed when the table is attached.
|
|
88
|
-
*
|
|
89
|
-
* @memberof SARViewer
|
|
90
|
-
*/
|
|
91
|
-
onTableAttached() {
|
|
92
|
-
this.sourceGrid = this.view.grid;
|
|
93
|
-
this.sourceGrid?.dataFrame?.setTag('dataType', 'peptides');
|
|
94
|
-
this.render();
|
|
95
|
+
await this.render();
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
/**
|
|
98
|
-
* Function that is executed when the viewer is detached from the table.
|
|
99
|
-
*
|
|
100
|
-
* @memberof SARViewer
|
|
101
|
-
*/
|
|
102
98
|
detach() {
|
|
103
99
|
this.subs.forEach((sub) => sub.unsubscribe());
|
|
104
100
|
}
|
|
@@ -109,7 +105,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
109
105
|
* @param {DG.Property} property New property.
|
|
110
106
|
* @memberof SARViewer
|
|
111
107
|
*/
|
|
112
|
-
onPropertyChanged(property: DG.Property) {
|
|
108
|
+
async onPropertyChanged(property: DG.Property) {
|
|
113
109
|
super.onPropertyChanged(property);
|
|
114
110
|
|
|
115
111
|
if (!this.initialized) {
|
|
@@ -130,7 +126,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
130
126
|
}
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
this.render();
|
|
129
|
+
await this.render();
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
/**
|
|
@@ -144,41 +140,37 @@ export class SARViewer extends DG.JsViewer {
|
|
|
144
140
|
return;
|
|
145
141
|
|
|
146
142
|
//TODO: optimize. Don't calculate everything again if only view changes
|
|
147
|
-
if (
|
|
148
|
-
if (
|
|
149
|
-
await
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
this._initialBitset!, this.activityColumnName, this.statsDf!,
|
|
179
|
-
);
|
|
180
|
-
});
|
|
181
|
-
}
|
|
143
|
+
if (typeof this.dataFrame !== 'undefined' && this.activityColumnName && this.sourceGrid) {
|
|
144
|
+
if (computeData) {
|
|
145
|
+
await this.controller!.updateData(this.dataFrame, this.activityColumnName, this.scaling, this.sourceGrid,
|
|
146
|
+
this.bidirectionalAnalysis, this._initialBitset, this.grouping);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (this.viewerGrid !== null && this.viewerVGrid !== null) {
|
|
150
|
+
$(this.root).empty();
|
|
151
|
+
const title = ui.h1(this._name, {style: {'align-self': 'center'}});
|
|
152
|
+
const gridRoot = this.viewerGrid.root;
|
|
153
|
+
gridRoot.style.width = 'auto';
|
|
154
|
+
this.root.appendChild(ui.divV([title, gridRoot]));
|
|
155
|
+
this.viewerGrid.dataFrame!.onCurrentCellChanged.subscribe((_) => {
|
|
156
|
+
this.currentBitset = applyBitset(
|
|
157
|
+
this.dataFrame!, this.viewerGrid!, this.aminoAcidResidue,
|
|
158
|
+
this.groupMapping!, this._initialBitset!, this.filterMode,
|
|
159
|
+
) ?? this.currentBitset;
|
|
160
|
+
syncGridsFunc(false, this.viewerGrid!, this.viewerVGrid!, this.aminoAcidResidue);
|
|
161
|
+
});
|
|
162
|
+
this.viewerVGrid.dataFrame!.onCurrentCellChanged.subscribe((_) => {
|
|
163
|
+
syncGridsFunc(true, this.viewerGrid!, this.viewerVGrid!, this.aminoAcidResidue);
|
|
164
|
+
});
|
|
165
|
+
this.dataFrame.onRowsFiltering.subscribe((_) => {
|
|
166
|
+
sourceFilteringFunc(this.filterMode, this.dataFrame!, this.currentBitset!, this._initialBitset!);
|
|
167
|
+
});
|
|
168
|
+
grok.events.onAccordionConstructed.subscribe((accordion: DG.Accordion) => {
|
|
169
|
+
accordionFunc(
|
|
170
|
+
accordion, this.viewerGrid!, this.aminoAcidResidue,
|
|
171
|
+
this._initialBitset!, this.activityColumnName, this.statsDf!,
|
|
172
|
+
);
|
|
173
|
+
});
|
|
182
174
|
}
|
|
183
175
|
}
|
|
184
176
|
//fixes viewers not rendering immediately after analyze.
|
|
@@ -195,27 +187,31 @@ export class SARViewer extends DG.JsViewer {
|
|
|
195
187
|
*/
|
|
196
188
|
export class SARViewerVertical extends DG.JsViewer {
|
|
197
189
|
viewerVGrid: DG.Grid | null;
|
|
190
|
+
// model: PeptidesModel | null;
|
|
191
|
+
protected _name = 'Sequence-Activity relationship';
|
|
192
|
+
controller: PeptidesController | null;
|
|
198
193
|
|
|
199
|
-
/**
|
|
200
|
-
* Creates an instance of SARViewerVertical.
|
|
201
|
-
*
|
|
202
|
-
* @memberof SARViewerVertical
|
|
203
|
-
*/
|
|
204
194
|
constructor() {
|
|
205
195
|
super();
|
|
206
196
|
|
|
207
197
|
this.viewerVGrid = null;
|
|
208
|
-
this.
|
|
198
|
+
this.controller = null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get name() {
|
|
202
|
+
return this._name;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
onTableAttached(): void {
|
|
206
|
+
// this.model = PeptidesModel.getOrInit(this.dataFrame!);
|
|
207
|
+
this.controller = PeptidesController.getInstance(this.dataFrame!);
|
|
208
|
+
|
|
209
|
+
this.subs.push(this.controller.onSARVGridChanged.subscribe((data) => {
|
|
209
210
|
this.viewerVGrid = data;
|
|
210
211
|
this.render();
|
|
211
212
|
}));
|
|
212
213
|
}
|
|
213
214
|
|
|
214
|
-
/**
|
|
215
|
-
* Viewer render function.
|
|
216
|
-
*
|
|
217
|
-
* @memberof SARViewerVertical
|
|
218
|
-
*/
|
|
219
215
|
render() {
|
|
220
216
|
if (this.viewerVGrid) {
|
|
221
217
|
$(this.root).empty();
|
|
@@ -225,19 +221,15 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
225
221
|
}
|
|
226
222
|
}
|
|
227
223
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
viewerGrid: DG.Grid,
|
|
231
|
-
viewerVGrid: DG.Grid,
|
|
232
|
-
aminoAcidResidue: string,
|
|
233
|
-
) { //TODO: refactor, move
|
|
224
|
+
//TODO: refactor, move
|
|
225
|
+
function syncGridsFunc(sourceVertical: boolean, viewerGrid: DG.Grid, viewerVGrid: DG.Grid, aminoAcidResidue: string) {
|
|
234
226
|
if (viewerGrid && viewerGrid.dataFrame && viewerVGrid && viewerVGrid.dataFrame) {
|
|
235
227
|
if (sourceVertical) {
|
|
236
228
|
const dfCell = viewerVGrid.dataFrame.currentCell;
|
|
237
|
-
if (dfCell.column === null || dfCell.column.name !== '
|
|
229
|
+
if (dfCell.column === null || dfCell.column.name !== 'Diff')
|
|
238
230
|
return;
|
|
239
231
|
|
|
240
|
-
const otherColName: string = viewerVGrid.dataFrame.get('
|
|
232
|
+
const otherColName: string = viewerVGrid.dataFrame.get('Pos', dfCell.rowIndex);
|
|
241
233
|
const otherRowName: string = viewerVGrid.dataFrame.get(aminoAcidResidue, dfCell.rowIndex);
|
|
242
234
|
let otherRowIndex = -1;
|
|
243
235
|
for (let i = 0; i < viewerGrid.dataFrame.rowCount; i++) {
|
|
@@ -259,24 +251,20 @@ function syncGridsFunc(
|
|
|
259
251
|
for (let i = 0; i < viewerVGrid.dataFrame.rowCount; i++) {
|
|
260
252
|
if (
|
|
261
253
|
viewerVGrid.dataFrame.get(aminoAcidResidue, i) === otherAAR &&
|
|
262
|
-
viewerVGrid.dataFrame.get('
|
|
254
|
+
viewerVGrid.dataFrame.get('Pos', i) === otherPos
|
|
263
255
|
) {
|
|
264
256
|
otherRowIndex = i;
|
|
265
257
|
break;
|
|
266
258
|
}
|
|
267
259
|
}
|
|
268
260
|
if (otherRowIndex !== -1)
|
|
269
|
-
viewerVGrid.dataFrame.currentCell = viewerVGrid.dataFrame.cell(otherRowIndex, '
|
|
261
|
+
viewerVGrid.dataFrame.currentCell = viewerVGrid.dataFrame.cell(otherRowIndex, 'Diff');
|
|
270
262
|
}
|
|
271
263
|
}
|
|
272
264
|
}
|
|
273
265
|
|
|
274
266
|
function sourceFilteringFunc(
|
|
275
|
-
filterMode: boolean,
|
|
276
|
-
dataFrame: DG.DataFrame,
|
|
277
|
-
currentBitset: DG.BitSet,
|
|
278
|
-
initialBitset: DG.BitSet,
|
|
279
|
-
) {
|
|
267
|
+
filterMode: boolean, dataFrame: DG.DataFrame, currentBitset: DG.BitSet, initialBitset: DG.BitSet) {
|
|
280
268
|
if (filterMode) {
|
|
281
269
|
dataFrame.selection.setAll(false, false);
|
|
282
270
|
dataFrame.filter.copyFrom(currentBitset);
|
|
@@ -287,13 +275,8 @@ function sourceFilteringFunc(
|
|
|
287
275
|
}
|
|
288
276
|
|
|
289
277
|
function applyBitset(
|
|
290
|
-
dataFrame: DG.DataFrame,
|
|
291
|
-
|
|
292
|
-
aminoAcidResidue: string,
|
|
293
|
-
groupMapping: StringDictionary,
|
|
294
|
-
initialBitset: DG.BitSet,
|
|
295
|
-
filterMode: boolean,
|
|
296
|
-
) {
|
|
278
|
+
dataFrame: DG.DataFrame, viewerGrid: DG.Grid, aminoAcidResidue: string, groupMapping: StringDictionary,
|
|
279
|
+
initialBitset: DG.BitSet, filterMode: boolean) {
|
|
297
280
|
let currentBitset = null;
|
|
298
281
|
if (
|
|
299
282
|
viewerGrid.dataFrame &&
|
|
@@ -330,13 +313,8 @@ function applyBitset(
|
|
|
330
313
|
}
|
|
331
314
|
|
|
332
315
|
function accordionFunc(
|
|
333
|
-
accordion: DG.Accordion,
|
|
334
|
-
|
|
335
|
-
aminoAcidResidue: string,
|
|
336
|
-
initialBitset: DG.BitSet,
|
|
337
|
-
activityColumnName: string,
|
|
338
|
-
statsDf: DG.DataFrame,
|
|
339
|
-
) {
|
|
316
|
+
accordion: DG.Accordion, viewerGrid: DG.Grid, aminoAcidResidue: string, initialBitset: DG.BitSet,
|
|
317
|
+
activityColumnName: string, statsDf: DG.DataFrame) {
|
|
340
318
|
if (accordion.context instanceof DG.RowGroup) {
|
|
341
319
|
const originalDf: DG.DataFrame = DG.toJs(accordion.context.dataFrame);
|
|
342
320
|
const viewerDf = viewerGrid.dataFrame;
|
|
@@ -381,7 +359,7 @@ function accordionFunc(
|
|
|
381
359
|
|
|
382
360
|
const tableMap: StringDictionary = {'Statistics:': ''};
|
|
383
361
|
for (const colName of new Set(['Count', 'pValue', 'Mean difference'])) {
|
|
384
|
-
const query = `${aminoAcidResidue} = ${currentAAR} and
|
|
362
|
+
const query = `${aminoAcidResidue} = ${currentAAR} and Pos = ${currentPosition}`;
|
|
385
363
|
const textNum = statsDf.groupBy([colName]).where(query).aggregate().get(colName, 0);
|
|
386
364
|
// const text = textNum === 0 ? '<0.01' : `${colName === 'Count' ? textNum : textNum.toFixed(2)}`;
|
|
387
365
|
const text = colName === 'Count' ? `${textNum}` : textNum < 0.01 ? '<0.01' : textNum.toFixed(2);
|