@datagrok/peptides 0.8.5 → 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/.eslintrc.json +12 -2
- package/files/aligned.csv +648 -3
- package/files/aligned_2.csv +10275 -3
- package/package.json +12 -14
- package/setup.cmd +18 -0
- package/setup.sh +15 -0
- package/src/describe.ts +131 -136
- package/src/model.ts +98 -76
- package/src/monomer-library.ts +184 -0
- package/src/package-test.ts +4 -3
- package/src/package.ts +76 -23
- package/src/peptides.ts +223 -108
- package/src/tests/msa-tests.ts +27 -0
- package/src/tests/peptide-space-test.ts +46 -9
- package/src/tests/peptides-tests.ts +58 -21
- package/src/tests/test-data.ts +649 -0
- package/src/tests/utils.ts +56 -16
- package/src/utils/cell-renderer.ts +211 -58
- package/src/utils/chem-palette.ts +86 -45
- package/src/utils/molecular-measure.ts +3 -4
- package/src/utils/multiple-sequence-alignment.ts +3 -4
- package/src/utils/peptide-similarity-space.ts +44 -37
- package/src/utils/split-aligned.ts +58 -58
- package/src/viewers/logo-viewer.ts +14 -15
- package/src/viewers/sar-viewer.ts +101 -124
- package/src/viewers/stacked-barchart-viewer.ts +360 -365
- package/src/viewers/subst-viewer.ts +115 -71
- package/src/widgets/analyze-peptides.ts +31 -31
- package/src/widgets/manual-alignment.ts +12 -7
- package/src/widgets/multiple-sequence-alignment.ts +9 -0
- package/src/widgets/peptide-molecule.ts +9 -8
- package/src/widgets/subst-table.ts +65 -0
- package/src/workers/dimensionality-reducer.ts +2 -1
- package/tsconfig.json +1 -1
|
@@ -3,8 +3,9 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
|
-
|
|
7
|
-
import {
|
|
6
|
+
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
7
|
+
import {PeptidesController} from '../peptides';
|
|
8
|
+
// import {PeptidesModel} from '../model';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Structure-activity relationship viewer.
|
|
@@ -27,8 +28,11 @@ export class SARViewer extends DG.JsViewer {
|
|
|
27
28
|
protected _initialBitset: DG.BitSet | null;
|
|
28
29
|
protected viewerVGrid: DG.Grid | null;
|
|
29
30
|
protected currentBitset: DG.BitSet | null;
|
|
30
|
-
grouping: boolean;
|
|
31
|
-
groupMapping:
|
|
31
|
+
protected grouping: boolean;
|
|
32
|
+
protected groupMapping: StringDictionary | null;
|
|
33
|
+
// model: PeptidesModel | null;
|
|
34
|
+
protected _name: string = 'Monomer-Positions';
|
|
35
|
+
protected controller: PeptidesController | null;
|
|
32
36
|
// protected pValueThreshold: number;
|
|
33
37
|
// protected amountOfBestAARs: number;
|
|
34
38
|
// duplicatesHandingMethod: string;
|
|
@@ -50,6 +54,8 @@ export class SARViewer extends DG.JsViewer {
|
|
|
50
54
|
this._initialBitset = null;
|
|
51
55
|
this.viewGridInitialized = false;
|
|
52
56
|
this.currentBitset = null;
|
|
57
|
+
// this.model = null;
|
|
58
|
+
this.controller = null;
|
|
53
59
|
|
|
54
60
|
//TODO: find a way to restrict activityColumnName to accept only numerical columns (double even better)
|
|
55
61
|
this.activityColumnName = this.string('activityColumnName');
|
|
@@ -57,47 +63,38 @@ export class SARViewer extends DG.JsViewer {
|
|
|
57
63
|
this.filterMode = this.bool('filterMode', false);
|
|
58
64
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
59
65
|
this.grouping = this.bool('grouping', false);
|
|
60
|
-
// this.pValueThreshold = this.float('pValueThreshold', 0.1);
|
|
61
|
-
// this.amountOfBestAARs = this.int('amountOfBestAAR', 1);
|
|
62
|
-
// this.duplicatesHandingMethod = this.string('duplicatesHandlingMethod', 'median', {choices: ['median']});
|
|
63
66
|
|
|
64
67
|
this.sourceGrid = null;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*/
|
|
70
|
+
get name() {
|
|
71
|
+
return this._name;
|
|
72
|
+
}
|
|
73
|
+
|
|
72
74
|
init() {
|
|
73
75
|
this._initialBitset = this.dataFrame!.filter.clone();
|
|
74
76
|
this.currentBitset = this._initialBitset.clone();
|
|
75
77
|
this.initialized = true;
|
|
76
|
-
|
|
77
|
-
|
|
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) => {
|
|
78
89
|
this.viewerGrid = data;
|
|
79
|
-
this.render();
|
|
90
|
+
this.render(false);
|
|
80
91
|
}));
|
|
81
|
-
this.subs.push(
|
|
82
|
-
this.subs.push(
|
|
83
|
-
}
|
|
92
|
+
this.subs.push(this.controller.onSARVGridChanged.subscribe((data) => this.viewerVGrid = data));
|
|
93
|
+
this.subs.push(this.controller.onGroupMappingChanged.subscribe((data) => this.groupMapping = data));
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
* Function that is executed when the table is attached.
|
|
87
|
-
*
|
|
88
|
-
* @memberof SARViewer
|
|
89
|
-
*/
|
|
90
|
-
onTableAttached() {
|
|
91
|
-
this.sourceGrid = this.view.grid;
|
|
92
|
-
this.sourceGrid?.dataFrame?.setTag('dataType', 'peptides');
|
|
93
|
-
this.render();
|
|
95
|
+
await this.render();
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
/**
|
|
97
|
-
* Function that is executed when the viewer is detached from the table.
|
|
98
|
-
*
|
|
99
|
-
* @memberof SARViewer
|
|
100
|
-
*/
|
|
101
98
|
detach() {
|
|
102
99
|
this.subs.forEach((sub) => sub.unsubscribe());
|
|
103
100
|
}
|
|
@@ -108,7 +105,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
108
105
|
* @param {DG.Property} property New property.
|
|
109
106
|
* @memberof SARViewer
|
|
110
107
|
*/
|
|
111
|
-
onPropertyChanged(property: DG.Property) {
|
|
108
|
+
async onPropertyChanged(property: DG.Property) {
|
|
112
109
|
super.onPropertyChanged(property);
|
|
113
110
|
|
|
114
111
|
if (!this.initialized) {
|
|
@@ -129,7 +126,7 @@ export class SARViewer extends DG.JsViewer {
|
|
|
129
126
|
}
|
|
130
127
|
}
|
|
131
128
|
|
|
132
|
-
this.render();
|
|
129
|
+
await this.render();
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
/**
|
|
@@ -139,45 +136,41 @@ export class SARViewer extends DG.JsViewer {
|
|
|
139
136
|
* @memberof SARViewer
|
|
140
137
|
*/
|
|
141
138
|
async render(computeData = true) {
|
|
142
|
-
if (!this.initialized)
|
|
139
|
+
if (!this.initialized)
|
|
143
140
|
return;
|
|
144
|
-
|
|
141
|
+
|
|
145
142
|
//TODO: optimize. Don't calculate everything again if only view changes
|
|
146
|
-
if (
|
|
147
|
-
if (
|
|
148
|
-
await
|
|
149
|
-
this.
|
|
150
|
-
|
|
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
|
-
this._initialBitset!, this.activityColumnName, this.statsDf!,
|
|
178
|
-
);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
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
|
+
});
|
|
181
174
|
}
|
|
182
175
|
}
|
|
183
176
|
//fixes viewers not rendering immediately after analyze.
|
|
@@ -194,27 +187,31 @@ export class SARViewer extends DG.JsViewer {
|
|
|
194
187
|
*/
|
|
195
188
|
export class SARViewerVertical extends DG.JsViewer {
|
|
196
189
|
viewerVGrid: DG.Grid | null;
|
|
190
|
+
// model: PeptidesModel | null;
|
|
191
|
+
protected _name = 'Sequence-Activity relationship';
|
|
192
|
+
controller: PeptidesController | null;
|
|
197
193
|
|
|
198
|
-
/**
|
|
199
|
-
* Creates an instance of SARViewerVertical.
|
|
200
|
-
*
|
|
201
|
-
* @memberof SARViewerVertical
|
|
202
|
-
*/
|
|
203
194
|
constructor() {
|
|
204
195
|
super();
|
|
205
196
|
|
|
206
197
|
this.viewerVGrid = null;
|
|
207
|
-
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) => {
|
|
208
210
|
this.viewerVGrid = data;
|
|
209
211
|
this.render();
|
|
210
212
|
}));
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
/**
|
|
214
|
-
* Viewer render function.
|
|
215
|
-
*
|
|
216
|
-
* @memberof SARViewerVertical
|
|
217
|
-
*/
|
|
218
215
|
render() {
|
|
219
216
|
if (this.viewerVGrid) {
|
|
220
217
|
$(this.root).empty();
|
|
@@ -224,19 +221,15 @@ export class SARViewerVertical extends DG.JsViewer {
|
|
|
224
221
|
}
|
|
225
222
|
}
|
|
226
223
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
viewerGrid: DG.Grid,
|
|
230
|
-
viewerVGrid: DG.Grid,
|
|
231
|
-
aminoAcidResidue: string,
|
|
232
|
-
) { //TODO: refactor, move
|
|
224
|
+
//TODO: refactor, move
|
|
225
|
+
function syncGridsFunc(sourceVertical: boolean, viewerGrid: DG.Grid, viewerVGrid: DG.Grid, aminoAcidResidue: string) {
|
|
233
226
|
if (viewerGrid && viewerGrid.dataFrame && viewerVGrid && viewerVGrid.dataFrame) {
|
|
234
227
|
if (sourceVertical) {
|
|
235
228
|
const dfCell = viewerVGrid.dataFrame.currentCell;
|
|
236
|
-
if (dfCell.column === null || dfCell.column.name !== '
|
|
229
|
+
if (dfCell.column === null || dfCell.column.name !== 'Diff')
|
|
237
230
|
return;
|
|
238
|
-
|
|
239
|
-
const otherColName: string = viewerVGrid.dataFrame.get('
|
|
231
|
+
|
|
232
|
+
const otherColName: string = viewerVGrid.dataFrame.get('Pos', dfCell.rowIndex);
|
|
240
233
|
const otherRowName: string = viewerVGrid.dataFrame.get(aminoAcidResidue, dfCell.rowIndex);
|
|
241
234
|
let otherRowIndex = -1;
|
|
242
235
|
for (let i = 0; i < viewerGrid.dataFrame.rowCount; i++) {
|
|
@@ -245,39 +238,33 @@ function syncGridsFunc(
|
|
|
245
238
|
break;
|
|
246
239
|
}
|
|
247
240
|
}
|
|
248
|
-
if (otherRowIndex !== -1)
|
|
241
|
+
if (otherRowIndex !== -1)
|
|
249
242
|
viewerGrid.dataFrame.currentCell = viewerGrid.dataFrame.cell(otherRowIndex, otherColName);
|
|
250
|
-
}
|
|
251
243
|
} else {
|
|
252
244
|
const otherPos: string = viewerGrid.dataFrame.currentCol?.name;
|
|
253
|
-
if (typeof otherPos === 'undefined' && otherPos !== aminoAcidResidue)
|
|
245
|
+
if (typeof otherPos === 'undefined' && otherPos !== aminoAcidResidue)
|
|
254
246
|
return;
|
|
255
|
-
|
|
247
|
+
|
|
256
248
|
const otherAAR: string =
|
|
257
249
|
viewerGrid.dataFrame.get(aminoAcidResidue, viewerGrid.dataFrame.currentRowIdx);
|
|
258
250
|
let otherRowIndex = -1;
|
|
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
|
-
if (otherRowIndex !== -1)
|
|
269
|
-
viewerVGrid.dataFrame.currentCell = viewerVGrid.dataFrame.cell(otherRowIndex, '
|
|
270
|
-
}
|
|
260
|
+
if (otherRowIndex !== -1)
|
|
261
|
+
viewerVGrid.dataFrame.currentCell = viewerVGrid.dataFrame.cell(otherRowIndex, 'Diff');
|
|
271
262
|
}
|
|
272
263
|
}
|
|
273
264
|
}
|
|
274
265
|
|
|
275
266
|
function sourceFilteringFunc(
|
|
276
|
-
filterMode: boolean,
|
|
277
|
-
dataFrame: DG.DataFrame,
|
|
278
|
-
currentBitset: DG.BitSet,
|
|
279
|
-
initialBitset: DG.BitSet,
|
|
280
|
-
) {
|
|
267
|
+
filterMode: boolean, dataFrame: DG.DataFrame, currentBitset: DG.BitSet, initialBitset: DG.BitSet) {
|
|
281
268
|
if (filterMode) {
|
|
282
269
|
dataFrame.selection.setAll(false, false);
|
|
283
270
|
dataFrame.filter.copyFrom(currentBitset);
|
|
@@ -288,13 +275,8 @@ function sourceFilteringFunc(
|
|
|
288
275
|
}
|
|
289
276
|
|
|
290
277
|
function applyBitset(
|
|
291
|
-
dataFrame: DG.DataFrame,
|
|
292
|
-
|
|
293
|
-
aminoAcidResidue: string,
|
|
294
|
-
groupMapping: {[key: string]: string},
|
|
295
|
-
initialBitset: DG.BitSet,
|
|
296
|
-
filterMode: boolean,
|
|
297
|
-
) {
|
|
278
|
+
dataFrame: DG.DataFrame, viewerGrid: DG.Grid, aminoAcidResidue: string, groupMapping: StringDictionary,
|
|
279
|
+
initialBitset: DG.BitSet, filterMode: boolean) {
|
|
298
280
|
let currentBitset = null;
|
|
299
281
|
if (
|
|
300
282
|
viewerGrid.dataFrame &&
|
|
@@ -310,9 +292,9 @@ function applyBitset(
|
|
|
310
292
|
const aarLabel = `${currentAAR === '-' ? 'Empty' : currentAAR} - ${currentPosition}`;
|
|
311
293
|
|
|
312
294
|
let splitCol = dataFrame.col(splitColName);
|
|
313
|
-
if (!splitCol)
|
|
295
|
+
if (!splitCol)
|
|
314
296
|
splitCol = dataFrame.columns.addNew(splitColName, 'string');
|
|
315
|
-
|
|
297
|
+
|
|
316
298
|
|
|
317
299
|
const isChosen = (i: number) => groupMapping[dataFrame!.get(currentPosition, i)] === currentAAR;
|
|
318
300
|
splitCol!.init((i) => isChosen(i) ? aarLabel : otherLabel);
|
|
@@ -331,13 +313,8 @@ function applyBitset(
|
|
|
331
313
|
}
|
|
332
314
|
|
|
333
315
|
function accordionFunc(
|
|
334
|
-
accordion: DG.Accordion,
|
|
335
|
-
|
|
336
|
-
aminoAcidResidue: string,
|
|
337
|
-
initialBitset: DG.BitSet,
|
|
338
|
-
activityColumnName: string,
|
|
339
|
-
statsDf: DG.DataFrame,
|
|
340
|
-
) {
|
|
316
|
+
accordion: DG.Accordion, viewerGrid: DG.Grid, aminoAcidResidue: string, initialBitset: DG.BitSet,
|
|
317
|
+
activityColumnName: string, statsDf: DG.DataFrame) {
|
|
341
318
|
if (accordion.context instanceof DG.RowGroup) {
|
|
342
319
|
const originalDf: DG.DataFrame = DG.toJs(accordion.context.dataFrame);
|
|
343
320
|
const viewerDf = viewerGrid.dataFrame;
|
|
@@ -363,9 +340,9 @@ function accordionFunc(
|
|
|
363
340
|
const elements: (HTMLLabelElement | HTMLElement)[] = [currentLabel, otherLabel];
|
|
364
341
|
|
|
365
342
|
const distPane = accordion.getPane('Distribution');
|
|
366
|
-
if (distPane)
|
|
343
|
+
if (distPane)
|
|
367
344
|
accordion.removePane(distPane);
|
|
368
|
-
|
|
345
|
+
|
|
369
346
|
accordion.addPane('Distribution', () => {
|
|
370
347
|
const hist = originalDf.clone(initialBitset).plot.histogram({
|
|
371
348
|
// const hist = originalDf.plot.histogram({
|
|
@@ -380,9 +357,9 @@ function accordionFunc(
|
|
|
380
357
|
hist.style.width = 'auto';
|
|
381
358
|
elements.push(hist);
|
|
382
359
|
|
|
383
|
-
const tableMap:
|
|
360
|
+
const tableMap: StringDictionary = {'Statistics:': ''};
|
|
384
361
|
for (const colName of new Set(['Count', 'pValue', 'Mean difference'])) {
|
|
385
|
-
const query = `${aminoAcidResidue} = ${currentAAR} and
|
|
362
|
+
const query = `${aminoAcidResidue} = ${currentAAR} and Pos = ${currentPosition}`;
|
|
386
363
|
const textNum = statsDf.groupBy([colName]).where(query).aggregate().get(colName, 0);
|
|
387
364
|
// const text = textNum === 0 ? '<0.01' : `${colName === 'Count' ? textNum : textNum.toFixed(2)}`;
|
|
388
365
|
const text = colName === 'Count' ? `${textNum}` : textNum < 0.01 ? '<0.01' : textNum.toFixed(2);
|