@datagrok/peptides 1.0.2 → 1.2.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/dist/package-test.js +770 -475
- package/dist/package.js +914 -490
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +162 -163
- package/package.json +10 -11
- package/src/__jest__/remote.test.ts +5 -4
- package/src/__jest__/test-node.ts +3 -2
- package/src/model.ts +71 -79
- package/src/package-test.ts +0 -1
- package/src/package.ts +8 -23
- package/src/tests/core.ts +13 -3
- package/src/tests/peptide-space-test.ts +7 -7
- package/src/tests/utils.ts +3 -8
- package/src/utils/cell-renderer.ts +5 -5
- package/src/utils/constants.ts +1 -1
- package/src/utils/invariant-map.ts +163 -0
- package/src/utils/misc.ts +10 -28
- package/src/utils/{filtering-statistics.ts → statistics.ts} +0 -0
- package/src/viewers/sar-viewer.ts +4 -18
- package/src/widgets/analyze-peptides.ts +14 -6
- package/src/widgets/distribution.ts +22 -21
- package/src/widgets/manual-alignment.ts +3 -2
- package/src/widgets/{subst-table.ts → mutation-cliffs.ts} +6 -5
- package/helm/JSDraw/Pistoia.HELM.js +0 -27
- package/logojs-react/index.d.ts +0 -1
- package/src/utils/multiple-sequence-alignment.ts +0 -106
- package/src/utils/multivariate-analysis.ts +0 -76
- package/test-Peptides-4f0c8bae6479-74cbfe68.html +0 -256
package/src/tests/utils.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
createDimensinalityReducingWorker,
|
|
7
7
|
IReduceDimensionalityResult,
|
|
8
8
|
} from '@datagrok-libraries/ml/src/workers/dimensionality-reducing-worker-creator';
|
|
9
|
-
import {runKalign} from '../utils/multiple-sequence-alignment';
|
|
10
9
|
import {StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -39,11 +38,10 @@ export async function _testViewerIsDrawing(table: DG.DataFrame, view: DG.TableVi
|
|
|
39
38
|
export async function _testDimensionalityReducer(
|
|
40
39
|
columnData: Array<string>, method: StringMetrics, measure: string): Promise<void> {
|
|
41
40
|
const cyclesCount = 100;
|
|
42
|
-
let embcols;
|
|
43
41
|
|
|
44
42
|
const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
|
|
45
43
|
{data: columnData, metric: measure as StringMetrics}, method, {cycles: cyclesCount});
|
|
46
|
-
embcols = reduceDimRes.embedding;
|
|
44
|
+
const embcols = reduceDimRes.embedding;
|
|
47
45
|
|
|
48
46
|
const [X, Y] = embcols as Array<Float32Array>;
|
|
49
47
|
|
|
@@ -65,12 +63,9 @@ export async function _testDimensionalityReducer(
|
|
|
65
63
|
*/
|
|
66
64
|
export async function _testPeptideSimilaritySpaceViewer(table: DG.DataFrame, alignedSequencesColumn: DG.Column,
|
|
67
65
|
method: string, measure: string, cyclesCount: number): Promise<void> {
|
|
68
|
-
|
|
69
|
-
let df: DG.DataFrame;
|
|
70
|
-
|
|
71
|
-
viewer = await createPeptideSimilaritySpaceViewer(
|
|
66
|
+
const viewer = await createPeptideSimilaritySpaceViewer(
|
|
72
67
|
table, method, measure, cyclesCount, undefined, alignedSequencesColumn);
|
|
73
|
-
df = viewer.dataFrame;
|
|
68
|
+
const df = viewer.dataFrame;
|
|
74
69
|
|
|
75
70
|
const axesNames = ['~X', '~Y', '~MW'];
|
|
76
71
|
const axes = axesNames.map((v) => df.getCol(v).getRawData() as Float32Array);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {SeqPaletteBase} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
|
|
4
4
|
import * as C from './constants';
|
|
@@ -63,8 +63,8 @@ export function measureAAR(s: string): number {
|
|
|
63
63
|
|
|
64
64
|
export function renderSARCell(canvasContext: CanvasRenderingContext2D, currentAAR: string, currentPosition: string,
|
|
65
65
|
statsDf: DG.DataFrame, twoColorMode: boolean, mdCol: DG.Column<number>, bound: DG.Rect, cellValue: number,
|
|
66
|
-
currentSelection: types.SelectionObject, substitutionsInfo: types.SubstitutionsInfo
|
|
67
|
-
const queryAAR = `${C.COLUMNS_NAMES.
|
|
66
|
+
currentSelection: types.SelectionObject, substitutionsInfo: types.SubstitutionsInfo): void {
|
|
67
|
+
const queryAAR = `${C.COLUMNS_NAMES.MONOMER} = ${currentAAR}`;
|
|
68
68
|
const query = `${queryAAR} and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
|
|
69
69
|
const pVal: number = statsDf
|
|
70
70
|
.groupBy([C.COLUMNS_NAMES.P_VALUE])
|
|
@@ -101,7 +101,7 @@ export function renderSARCell(canvasContext: CanvasRenderingContext2D, currentAA
|
|
|
101
101
|
canvasContext.closePath();
|
|
102
102
|
|
|
103
103
|
canvasContext.fill();
|
|
104
|
-
if (substitutionsInfo) {
|
|
104
|
+
if (substitutionsInfo.size > 0) {
|
|
105
105
|
canvasContext.textBaseline = 'middle';
|
|
106
106
|
canvasContext.textAlign = 'center';
|
|
107
107
|
canvasContext.fillStyle = DG.Color.toHtml(DG.Color.getContrastColor(DG.Color.fromHtml(coef)));
|
|
@@ -136,7 +136,7 @@ export function renderBarchart(ctx: CanvasRenderingContext2D, col: DG.Column, mo
|
|
|
136
136
|
const yMargin = bounds.y + bounds.height * margin / 4;
|
|
137
137
|
const wMargin = bounds.width - bounds.width * margin * 2;
|
|
138
138
|
const hMargin = bounds.height - bounds.height * margin;
|
|
139
|
-
const barWidth =
|
|
139
|
+
const barWidth = 10;
|
|
140
140
|
ctx.fillStyle = 'black';
|
|
141
141
|
ctx.textBaseline = 'top';
|
|
142
142
|
ctx.font = `${hMargin * margin / 2}px`;
|
package/src/utils/constants.ts
CHANGED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
|
|
4
|
+
import * as C from './constants';
|
|
5
|
+
import {PeptidesModel} from '../model';
|
|
6
|
+
import {isGridCellInvalid} from './misc';
|
|
7
|
+
|
|
8
|
+
const CELL_SIZE = 20; // 20px cell height and width
|
|
9
|
+
|
|
10
|
+
export class InvariantMap extends DG.Filter {
|
|
11
|
+
model: PeptidesModel | null = null;
|
|
12
|
+
chosenCells: {[position: string]: string[]} = {};
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get caption(): string {return 'Invariant Map';}
|
|
19
|
+
|
|
20
|
+
get filterSummary(): string {
|
|
21
|
+
let summary = '';
|
|
22
|
+
for (const [pos, aarList] of Object.entries(this.chosenCells))
|
|
23
|
+
if (aarList.length > 0)
|
|
24
|
+
summary += `${pos}: ${aarList}\n`;
|
|
25
|
+
|
|
26
|
+
return summary;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get isFiltering(): boolean {return true && super.isFiltering;}
|
|
30
|
+
|
|
31
|
+
get isReadyToApplyFilter(): boolean {return this.model != null;}
|
|
32
|
+
|
|
33
|
+
async attach(df: DG.DataFrame): Promise<void> {
|
|
34
|
+
super.attach(df);
|
|
35
|
+
this.model = await PeptidesModel.getInstance(df);
|
|
36
|
+
this.render(true);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
saveState(): any {
|
|
40
|
+
const state = super.saveState();
|
|
41
|
+
state.chosenCells = JSON.stringify(this.chosenCells);
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
applyState(state: any): void {
|
|
46
|
+
super.applyState(state);
|
|
47
|
+
if (state.chosenCells) {
|
|
48
|
+
this.chosenCells = JSON.parse(state.chosenCells);
|
|
49
|
+
this.render();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
applyFilter(): void {
|
|
54
|
+
this.dataFrame?.filter.init((bitsetIndex) => {
|
|
55
|
+
for (const [position, aarList] of Object.entries(this.chosenCells)) {
|
|
56
|
+
if (aarList.length != 0 && !aarList.includes(this.dataFrame!.get(position, bitsetIndex)))
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
render(initChosenCells: boolean = false): void {
|
|
64
|
+
if (this.model == null)
|
|
65
|
+
return;
|
|
66
|
+
|
|
67
|
+
const invariantDf = this.model.statsDf.groupBy([C.COLUMNS_NAMES.MONOMER])
|
|
68
|
+
.pivot(C.COLUMNS_NAMES.POSITION)
|
|
69
|
+
.add('first', C.COLUMNS_NAMES.COUNT, '')
|
|
70
|
+
.aggregate();
|
|
71
|
+
invariantDf.getCol(C.COLUMNS_NAMES.MONOMER).semType = C.SEM_TYPES.MONOMER;
|
|
72
|
+
const orderedColNames = invariantDf.columns.names().sort((a, b) => {
|
|
73
|
+
const aInt = parseInt(a);
|
|
74
|
+
const bInt = parseInt(b);
|
|
75
|
+
if (isNaN(aInt))
|
|
76
|
+
return -1;
|
|
77
|
+
else if (isNaN(bInt))
|
|
78
|
+
return 1;
|
|
79
|
+
return aInt - bInt;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Create grid and set properties
|
|
83
|
+
const invariantGrid = invariantDf.plot.grid();
|
|
84
|
+
const gridCols = invariantGrid.columns;
|
|
85
|
+
gridCols.rowHeader!.visible = false;
|
|
86
|
+
gridCols.setOrder(orderedColNames);
|
|
87
|
+
|
|
88
|
+
for (let gridColIndex = 0; gridColIndex < gridCols.length; ++gridColIndex) {
|
|
89
|
+
const gridCol = gridCols.byIndex(gridColIndex)!
|
|
90
|
+
if (gridCol.name != C.COLUMNS_NAMES.MONOMER)
|
|
91
|
+
gridCol.width = CELL_SIZE;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (initChosenCells) {
|
|
95
|
+
this.chosenCells = {};
|
|
96
|
+
for (const col of invariantDf.columns)
|
|
97
|
+
if (col.name != C.COLUMNS_NAMES.MONOMER)
|
|
98
|
+
this.chosenCells[col.name] = [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
invariantGrid.root.addEventListener('click', (ev) => {
|
|
102
|
+
invariantDf.currentRowIdx = -1;
|
|
103
|
+
const gridCell = invariantGrid.hitTest(ev.offsetX, ev.offsetY);
|
|
104
|
+
if (isGridCellInvalid(gridCell) || gridCell!.tableColumn!.name == C.COLUMNS_NAMES.MONOMER)
|
|
105
|
+
return;
|
|
106
|
+
|
|
107
|
+
const position = gridCell!.tableColumn!.name;
|
|
108
|
+
const aar = invariantDf.get(C.COLUMNS_NAMES.MONOMER, gridCell!.tableRowIndex!);
|
|
109
|
+
const aarList = this.chosenCells[position];
|
|
110
|
+
const aarIndex = aarList.indexOf(aar);
|
|
111
|
+
|
|
112
|
+
if (aarIndex != -1)
|
|
113
|
+
aarList.splice(aarIndex, 1);
|
|
114
|
+
else
|
|
115
|
+
aarList.push(aar);
|
|
116
|
+
|
|
117
|
+
invariantGrid.invalidate();
|
|
118
|
+
this.applyFilter();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
invariantGrid.onCellRender.subscribe((args) => {
|
|
122
|
+
//FIXME: for some reason it doesn't work when I set right away
|
|
123
|
+
const gridProps = invariantGrid.props;
|
|
124
|
+
gridProps.allowBlockSelection = false;
|
|
125
|
+
gridProps.allowColSelection = false;
|
|
126
|
+
gridProps.allowRowSelection = false;
|
|
127
|
+
gridProps.allowEdit = false;
|
|
128
|
+
gridProps.rowHeight = CELL_SIZE;
|
|
129
|
+
|
|
130
|
+
const gc = args.cell;
|
|
131
|
+
const tableColName = gc.tableColumn?.name;
|
|
132
|
+
const tableRowIndex = gc.tableRowIndex;
|
|
133
|
+
|
|
134
|
+
if (isGridCellInvalid(gc) || tableColName == C.COLUMNS_NAMES.MONOMER ||
|
|
135
|
+
tableRowIndex == null || tableRowIndex == -1)
|
|
136
|
+
return;
|
|
137
|
+
|
|
138
|
+
const currentPosition: string = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
|
|
139
|
+
tableColName : invariantDf.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
|
|
140
|
+
const currentAAR: string = invariantDf.get(C.COLUMNS_NAMES.MONOMER, tableRowIndex);
|
|
141
|
+
const canvasContext = args.g;
|
|
142
|
+
const bound = args.bounds;
|
|
143
|
+
|
|
144
|
+
canvasContext.font = '10px Roboto';
|
|
145
|
+
canvasContext.textAlign = 'center';
|
|
146
|
+
canvasContext.textBaseline = 'middle';
|
|
147
|
+
canvasContext.fillStyle = '#000';
|
|
148
|
+
canvasContext.fillText(gc.cell.value, bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
|
|
149
|
+
|
|
150
|
+
const aarSelection = this.chosenCells[currentPosition];
|
|
151
|
+
if (aarSelection.includes(currentAAR)) {
|
|
152
|
+
canvasContext.strokeStyle = '#000';
|
|
153
|
+
canvasContext.lineWidth = 1;
|
|
154
|
+
canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
|
|
155
|
+
}
|
|
156
|
+
args.preventDefault();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const gridHost = ui.box(invariantGrid.root);
|
|
160
|
+
gridHost.style.width = '100%';
|
|
161
|
+
this.root.appendChild(gridHost);
|
|
162
|
+
}
|
|
163
|
+
}
|
package/src/utils/misc.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {AminoacidsPalettes} from '@datagrok-libraries/bio/src/aminoacids';
|
|
|
6
6
|
import {NucleotidesPalettes} from '@datagrok-libraries/bio/src/nucleotides';
|
|
7
7
|
import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
|
|
8
8
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
9
|
-
import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
10
9
|
|
|
11
10
|
export function getPalleteByType(paletteType: string): SeqPalette {
|
|
12
11
|
switch (paletteType) {
|
|
@@ -33,28 +32,6 @@ export function getSeparator(col: DG.Column<string>): string {
|
|
|
33
32
|
return col.getTag(C.TAGS.SEPARATOR) ?? '';
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export function splitAlignedPeptides(peptideColumn: DG.Column<string>): DG.DataFrame {
|
|
37
|
-
const splitter = WebLogo.getSplitterForColumn(peptideColumn);
|
|
38
|
-
const colLen = peptideColumn.length;
|
|
39
|
-
const resultDf = DG.DataFrame.create(colLen);
|
|
40
|
-
let monomerList = splitter(peptideColumn.get(0)!);
|
|
41
|
-
const columnList: DG.Column<string>[] = [];
|
|
42
|
-
|
|
43
|
-
// create columns and fill the first row for faster values filling in the next loop
|
|
44
|
-
for (let i = 0; i < monomerList.length; i++) {
|
|
45
|
-
const col = resultDf.columns.addNewString((i + 1).toString());
|
|
46
|
-
col.set(0, monomerList[i] || '-', false);
|
|
47
|
-
columnList.push(col);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (let rowIndex = 1; rowIndex < colLen; rowIndex++) {
|
|
51
|
-
monomerList = splitter(peptideColumn.get(rowIndex)!);
|
|
52
|
-
monomerList.forEach((monomer, colIndex) => columnList[colIndex].set(rowIndex, monomer || '-', false));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return resultDf;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
35
|
export function scaleActivity(
|
|
59
36
|
activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
|
|
60
37
|
): [DG.DataFrame, string] {
|
|
@@ -64,17 +41,17 @@ export function scaleActivity(
|
|
|
64
41
|
currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
|
|
65
42
|
const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
|
|
66
43
|
|
|
67
|
-
let formula = (v: number) => v;
|
|
44
|
+
let formula = (v: number): number => v;
|
|
68
45
|
let newColName = 'activity';
|
|
69
46
|
switch (activityScaling) {
|
|
70
47
|
case 'none':
|
|
71
48
|
break;
|
|
72
49
|
case 'lg':
|
|
73
|
-
formula = (v: number) => Math.log10(v);
|
|
50
|
+
formula = (v: number): number => Math.log10(v);
|
|
74
51
|
newColName = `Log10(${newColName})`;
|
|
75
52
|
break;
|
|
76
53
|
case '-lg':
|
|
77
|
-
formula = (v: number) => -Math.log10(v);
|
|
54
|
+
formula = (v: number): number => -Math.log10(v);
|
|
78
55
|
newColName = `-Log10(${newColName})`;
|
|
79
56
|
break;
|
|
80
57
|
default:
|
|
@@ -95,13 +72,13 @@ export function calculateBarsData(columns: DG.Column<string>[], selection: DG.Bi
|
|
|
95
72
|
|
|
96
73
|
for (let colIndex = 0; colIndex < columnsLen; colIndex++) {
|
|
97
74
|
const col = columns[colIndex];
|
|
98
|
-
dfStats[col.name] =
|
|
75
|
+
dfStats[col.name] = calculateSingleBarData(col, selection);
|
|
99
76
|
}
|
|
100
77
|
|
|
101
78
|
return dfStats;
|
|
102
79
|
}
|
|
103
80
|
|
|
104
|
-
export function
|
|
81
|
+
export function calculateSingleBarData(col: DG.Column<string>, selection: DG.BitSet): type.MonomerColStats {
|
|
105
82
|
const colLen = col.length;
|
|
106
83
|
const colStats: type.MonomerColStats = {};
|
|
107
84
|
col.categories.forEach((monomer) => colStats[monomer] = {count: 0, selected: 0});
|
|
@@ -114,3 +91,8 @@ export function calculateBarData(col: DG.Column<string>, selection: DG.BitSet):
|
|
|
114
91
|
|
|
115
92
|
return colStats;
|
|
116
93
|
}
|
|
94
|
+
|
|
95
|
+
export function isGridCellInvalid(gc: DG.GridCell | null): boolean {
|
|
96
|
+
return !gc || !gc.cell.value || !gc.tableColumn || gc.tableRowIndex == null || gc.tableRowIndex == -1 ||
|
|
97
|
+
gc.cell.value == DG.INT_NULL || gc.cell.value == DG.FLOAT_NULL;
|
|
98
|
+
}
|
|
File without changes
|
|
@@ -15,7 +15,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
15
15
|
model!: PeptidesModel;
|
|
16
16
|
scaling: string;
|
|
17
17
|
bidirectionalAnalysis: boolean;
|
|
18
|
-
showSubstitution: boolean;
|
|
19
18
|
maxSubstitutions: number;
|
|
20
19
|
minActivityDelta: number;
|
|
21
20
|
_titleHost = ui.divText('SAR Viewer', {id: 'pep-viewer-title'});
|
|
@@ -27,23 +26,20 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
27
26
|
|
|
28
27
|
this.scaling = this.string('scaling', 'none', {choices: ['none', 'lg', '-lg']});
|
|
29
28
|
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
this.minActivityDelta = this.float('minActivityDelta', 1);
|
|
29
|
+
this.maxSubstitutions = this.int('maxSubstitutions', 1);
|
|
30
|
+
this.minActivityDelta = this.float('minActivityDelta', 0);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
async onTableAttached(): Promise<void> {
|
|
36
34
|
super.onTableAttached();
|
|
37
35
|
this.sourceGrid = this.view?.grid ?? (grok.shell.v as DG.TableView).grid;
|
|
38
36
|
this.model = await PeptidesModel.getInstance(this.dataFrame);
|
|
39
|
-
// this.model.init(this.dataFrame);
|
|
40
37
|
this.helpUrl = '/help/domains/bio/peptides.md';
|
|
41
|
-
// await this.requestDataUpdate();
|
|
42
38
|
|
|
43
39
|
this.initProperties();
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
initProperties() {
|
|
42
|
+
initProperties(): void {
|
|
47
43
|
const props = this.model.usedProperties;
|
|
48
44
|
IS_PROPERTY_CHANGING = true;
|
|
49
45
|
for (const [propName, propVal] of Object.entries(props))
|
|
@@ -65,11 +61,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
65
61
|
this.viewerGrid?.invalidate();
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
// async requestDataUpdate(): Promise<void> {
|
|
69
|
-
// await this.model.updateData(this.scaling, this.sourceGrid, this.bidirectionalAnalysis,
|
|
70
|
-
// this.minActivityDelta, this.maxSubstitutions, this.showSubstitution);
|
|
71
|
-
// }
|
|
72
|
-
|
|
73
64
|
onPropertyChanged(property: DG.Property): void {
|
|
74
65
|
super.onPropertyChanged(property);
|
|
75
66
|
this.dataFrame.tags[property.name] = `${property.get(this)}`;
|
|
@@ -89,10 +80,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
89
80
|
}
|
|
90
81
|
}
|
|
91
82
|
|
|
92
|
-
if (!this.showSubstitution && ['maxSubstitutions', 'activityLimit'].includes(propName))
|
|
93
|
-
return;
|
|
94
|
-
|
|
95
|
-
// await this.requestDataUpdate();
|
|
96
83
|
this.model.updateDefault();
|
|
97
84
|
this.render(true);
|
|
98
85
|
}
|
|
@@ -102,7 +89,7 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
102
89
|
* Structure-activity relationship viewer.
|
|
103
90
|
*/
|
|
104
91
|
export class SARViewer extends SARViewerBase {
|
|
105
|
-
_titleHost = ui.divText('
|
|
92
|
+
_titleHost = ui.divText('Mutation Cliffs', {id: 'pep-viewer-title'});
|
|
106
93
|
_name = 'Structure-Activity Relationship';
|
|
107
94
|
|
|
108
95
|
constructor() {super();}
|
|
@@ -112,7 +99,6 @@ export class SARViewer extends SARViewerBase {
|
|
|
112
99
|
async onTableAttached(): Promise<void> {
|
|
113
100
|
await super.onTableAttached();
|
|
114
101
|
this.model.sarViewer ??= this;
|
|
115
|
-
// this.dataFrame.temp['sarViewer'] = this;
|
|
116
102
|
|
|
117
103
|
this.subs.push(this.model.onSARGridChanged.subscribe((data) => {
|
|
118
104
|
this.viewerGrid = data;
|
|
@@ -7,7 +7,6 @@ import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
|
7
7
|
import '../styles.css';
|
|
8
8
|
import * as C from '../utils/constants';
|
|
9
9
|
import {PeptidesModel} from '../model';
|
|
10
|
-
import {_package} from '../package';
|
|
11
10
|
import $ from 'cash-dom';
|
|
12
11
|
import {scaleActivity} from '../utils/misc';
|
|
13
12
|
|
|
@@ -17,9 +16,17 @@ import {scaleActivity} from '../utils/misc';
|
|
|
17
16
|
* @param {DG.Column} col Aligned sequence column
|
|
18
17
|
* @return {Promise<DG.Widget>} Widget containing peptide analysis */
|
|
19
18
|
export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
|
|
20
|
-
|
|
19
|
+
if (!col.tags['aligned']?.includes('MSA') && col.tags[DG.TAGS.UNITS].toLowerCase() != 'helm')
|
|
20
|
+
return new DG.Widget(ui.divText('Peptides analysis only works with aligned sequences'));
|
|
21
|
+
|
|
22
|
+
let funcs = DG.Func.find({package: 'Bio', name: 'webLogoViewer'});
|
|
21
23
|
if (funcs.length == 0)
|
|
22
24
|
return new DG.Widget(ui.label('Bio package is missing or out of date. Please install the latest version.'));
|
|
25
|
+
|
|
26
|
+
funcs = DG.Func.find({package: 'Helm', name: 'getMonomerLib'});
|
|
27
|
+
if (funcs.length == 0)
|
|
28
|
+
return new DG.Widget(ui.label('Helm package is missing or out of date. Please install the latest version.'));
|
|
29
|
+
|
|
23
30
|
let tempCol = null;
|
|
24
31
|
let scaledDf: DG.DataFrame;
|
|
25
32
|
let newScaledColName: string;
|
|
@@ -85,7 +92,7 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
|
|
|
85
92
|
|
|
86
93
|
export async function startAnalysis(
|
|
87
94
|
activityColumn: DG.Column<number> | null, alignedSeqCol: DG.Column<string>, currentDf: DG.DataFrame,
|
|
88
|
-
scaledDf: DG.DataFrame, newScaledColName: string
|
|
95
|
+
scaledDf: DG.DataFrame, newScaledColName: string): Promise<PeptidesModel | null> {
|
|
89
96
|
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
90
97
|
let model = null;
|
|
91
98
|
if (activityColumn?.type === DG.TYPE.FLOAT) {
|
|
@@ -104,14 +111,15 @@ export async function startAnalysis(
|
|
|
104
111
|
newDf.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newScaledColName;
|
|
105
112
|
// newDf.tags[C.PEPTIDES_ANALYSIS] = 'true';
|
|
106
113
|
|
|
107
|
-
const alignedSeqColUnits = alignedSeqCol.getTag(DG.TAGS.UNITS);
|
|
108
114
|
let monomerType = 'HELM_AA';
|
|
109
|
-
if (
|
|
115
|
+
if (alignedSeqCol.getTag(DG.TAGS.UNITS).toLowerCase() == 'helm') {
|
|
110
116
|
const sampleSeq = alignedSeqCol.get(0)!;
|
|
111
117
|
monomerType = sampleSeq.startsWith('PEPTIDE') ? 'HELM_AA' : 'HELM_BASE';
|
|
112
118
|
} else {
|
|
113
|
-
|
|
119
|
+
const alphabet = alignedSeqCol.tags[C.TAGS.ALPHABET];
|
|
120
|
+
monomerType = alphabet == 'DNA' || alphabet == 'RNA' ? 'HELM_BASE' : 'HELM_AA';
|
|
114
121
|
}
|
|
122
|
+
|
|
115
123
|
newDf.setTag('monomerType', monomerType);
|
|
116
124
|
|
|
117
125
|
model = await PeptidesModel.getInstance(newDf);
|
|
@@ -5,7 +5,7 @@ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations'
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
|
|
7
7
|
import * as C from '../utils/constants';
|
|
8
|
-
import {getStats, Stats} from '../utils/
|
|
8
|
+
import {getStats, Stats} from '../utils/statistics';
|
|
9
9
|
import {PeptidesModel} from '../model';
|
|
10
10
|
|
|
11
11
|
const allConst = 'All';
|
|
@@ -21,7 +21,7 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
21
21
|
let otherStr = '';
|
|
22
22
|
const useSelectedStr = model.isPeptideSpaceChangingBitset;
|
|
23
23
|
|
|
24
|
-
const updateDistributionHost = () => {
|
|
24
|
+
const updateDistributionHost = (): void => {
|
|
25
25
|
model.splitByPos = splitByPosition.value!;
|
|
26
26
|
model.splitByAAR = splitByAAR.value!;
|
|
27
27
|
const res: HTMLDivElement[] = [];
|
|
@@ -104,31 +104,32 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
104
104
|
} else {
|
|
105
105
|
const splitCol = table.col(C.COLUMNS_NAMES.SPLIT_COL);
|
|
106
106
|
if (!splitCol)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
107
|
+
res.push(ui.divText('No distribution'));
|
|
108
|
+
else {
|
|
109
|
+
otherStr = '';
|
|
110
|
+
if (useSelectedStr) {
|
|
111
|
+
aarStr = 'Selected';
|
|
112
|
+
otherStr = otherConst;
|
|
113
|
+
} else if (positionsLen) {
|
|
114
|
+
aarStr = '';
|
|
115
|
+
for (const position of positions)
|
|
116
|
+
aarStr += `${position}: {${selectionObject[position].join(', ')}}; `;
|
|
117
|
+
aarStr = aarStr.slice(0, aarStr.length - 2);
|
|
118
|
+
otherStr = otherConst;
|
|
119
|
+
}
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
|
|
122
|
+
const stats = getStats(activityScaledCol.getRawData(), table.selection);
|
|
123
|
+
const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr);
|
|
124
|
+
$(distributionRoot).addClass('d4-flex-col');
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
res.push(distributionRoot);
|
|
127
|
+
}
|
|
127
128
|
}
|
|
128
129
|
$(distributionHost).empty().append(res);
|
|
129
130
|
};
|
|
130
131
|
|
|
131
|
-
const setDefaultProperties = (input: DG.InputBase) => {
|
|
132
|
+
const setDefaultProperties = (input: DG.InputBase): void => {
|
|
132
133
|
input.enabled = positionsLen != 0;
|
|
133
134
|
$(input.root).find('.ui-input-editor').css('margin', '0px');
|
|
134
135
|
$(input.root).find('.ui-input-description').css('padding', '0px');
|
|
@@ -2,10 +2,11 @@ import * as ui from 'datagrok-api/ui';
|
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
|
|
6
|
+
|
|
5
7
|
import $ from 'cash-dom';
|
|
6
8
|
import '../styles.css';
|
|
7
9
|
import {PeptidesModel} from '../model';
|
|
8
|
-
import {splitAlignedPeptides} from '../utils/misc';
|
|
9
10
|
|
|
10
11
|
/** Manual sequence alignment widget.
|
|
11
12
|
*
|
|
@@ -19,7 +20,7 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column<string>, cur
|
|
|
19
20
|
const applyChangesBtn = ui.button('Apply', async () => {
|
|
20
21
|
const newSequence = sequenceInput.value;
|
|
21
22
|
const affectedRowIndex = currentDf.currentRowIdx;
|
|
22
|
-
const splitSequence =
|
|
23
|
+
const splitSequence = splitAlignedSequences(DG.Column.fromStrings('splitSequence', [newSequence]));
|
|
23
24
|
|
|
24
25
|
alignedSequenceCol.set(affectedRowIndex, newSequence);
|
|
25
26
|
for (const part of splitSequence.columns) {
|
|
@@ -5,13 +5,13 @@ import * as type from '../utils/types';
|
|
|
5
5
|
import {PeptidesModel} from '../model';
|
|
6
6
|
import {getSeparator} from '../utils/misc';
|
|
7
7
|
|
|
8
|
-
export function
|
|
8
|
+
export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
|
|
9
9
|
const substInfo = model.substitutionsInfo;
|
|
10
10
|
const currentCell = model.currentSelection;
|
|
11
11
|
const positions = Object.keys(currentCell);
|
|
12
12
|
|
|
13
13
|
if (!positions.length)
|
|
14
|
-
return new DG.Widget(ui.label('No
|
|
14
|
+
return new DG.Widget(ui.label('No mutations table generated'));
|
|
15
15
|
|
|
16
16
|
const substitutionsArray: string[] = [];
|
|
17
17
|
const deltaArray: number[] = [];
|
|
@@ -49,18 +49,19 @@ export function substitutionsWidget(table: DG.DataFrame, model: PeptidesModel):
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
if (!substitutionsArray.length)
|
|
52
|
-
return new DG.Widget(ui.label('No
|
|
52
|
+
return new DG.Widget(ui.label('No mutations table generated'));
|
|
53
53
|
|
|
54
|
-
const substCol = DG.Column.fromStrings('
|
|
54
|
+
const substCol = DG.Column.fromStrings('Mutation', substitutionsArray);
|
|
55
55
|
substCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
56
56
|
substCol.tags[C.TAGS.SEPARATOR] = getSeparator(alignedSeqCol);
|
|
57
57
|
substCol.tags[DG.TAGS.UNITS] = alignedSeqCol.tags[DG.TAGS.UNITS];
|
|
58
|
+
substCol.tags[DG.TAGS.CELL_RENDERER] = 'MacromoleculeDifference';
|
|
58
59
|
const toColName = '~to';
|
|
59
60
|
const hiddenSubstToAarCol = DG.Column.fromStrings(toColName, substitutedToArray);
|
|
60
61
|
const substTable =
|
|
61
62
|
DG.DataFrame.fromColumns([substCol, DG.Column.fromList('double', 'Delta', deltaArray), hiddenSubstToAarCol]);
|
|
62
63
|
|
|
63
|
-
const aminoToInput = ui.stringInput('
|
|
64
|
+
const aminoToInput = ui.stringInput('Mutated to:', '', () => {
|
|
64
65
|
const substitutedToAar = aminoToInput.stringValue;
|
|
65
66
|
if (substitutedToAar != '')
|
|
66
67
|
substTable.filter.init((idx) => hiddenSubstToAarCol.get(idx) === substitutedToAar);
|