@datagrok/peptides 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package-test.js +682 -613
- package/dist/package.js +779 -617
- package/package.json +5 -1
- package/src/model.ts +423 -222
- package/src/package.ts +16 -15
- package/src/styles.css +1 -0
- package/src/tests/core.ts +10 -9
- package/src/tests/peptide-space-test.ts +32 -32
- package/src/utils/cell-renderer.ts +39 -59
- package/src/utils/constants.ts +9 -2
- package/src/utils/misc.ts +12 -17
- package/src/utils/peptide-similarity-space.ts +2 -1
- package/src/utils/types.ts +1 -1
- package/src/viewers/logo-summary.ts +42 -0
- package/src/viewers/peptide-space-viewer.ts +6 -4
- package/src/viewers/sar-viewer.ts +64 -13
- package/src/widgets/distribution.ts +26 -11
- package/src/widgets/mutation-cliffs.ts +3 -2
- package/src/widgets/{analyze-peptides.ts → peptides.ts} +56 -28
- package/test-Peptides-8408d9b6ee67-ca232121.html +246 -0
- package/src/utils/invariant-map.ts +0 -163
|
@@ -14,7 +14,11 @@ const otherConst = 'Other';
|
|
|
14
14
|
export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
|
|
15
15
|
const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
16
16
|
const rowCount = activityScaledCol.length;
|
|
17
|
-
const selectionObject = model.
|
|
17
|
+
const selectionObject = model.mutationCliffsSelection;
|
|
18
|
+
let isMutationCliffsSelectionEmpty = true;
|
|
19
|
+
for (const aarList of Object.values(selectionObject))
|
|
20
|
+
isMutationCliffsSelectionEmpty &&= aarList.length === 0;
|
|
21
|
+
const clustersObject = model.logoSummarySelection;
|
|
18
22
|
const positions = Object.keys(selectionObject);
|
|
19
23
|
const positionsLen = positions.length;
|
|
20
24
|
let aarStr = allConst;
|
|
@@ -29,12 +33,16 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
29
33
|
otherStr = otherConst;
|
|
30
34
|
for (const position of positions) {
|
|
31
35
|
const posCol = table.getCol(position);
|
|
32
|
-
|
|
36
|
+
const aarList = selectionObject[position];
|
|
37
|
+
if (aarList.length === 0)
|
|
38
|
+
continue;
|
|
39
|
+
|
|
40
|
+
for (const aar of aarList) {
|
|
33
41
|
aarStr = `${position} : ${aar}`;
|
|
34
42
|
const splitCol = DG.Column.bool(C.COLUMNS_NAMES.SPLIT_COL, rowCount).init((i) => posCol.get(i) == aar);
|
|
35
43
|
|
|
36
44
|
const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
|
|
37
|
-
const currentStatsDf = model.
|
|
45
|
+
const currentStatsDf = model.monomerPositionStatsDf.rows.match({Pos: position, AAR: aar}).toDataFrame();
|
|
38
46
|
const stats: Stats = {
|
|
39
47
|
count: currentStatsDf.get(C.COLUMNS_NAMES.COUNT, 0),
|
|
40
48
|
ratio: currentStatsDf.get(C.COLUMNS_NAMES.RATIO, 0),
|
|
@@ -49,10 +57,13 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
49
57
|
}
|
|
50
58
|
} else if (splitByPosition.value) {
|
|
51
59
|
otherStr = otherConst;
|
|
52
|
-
const activityScaledData = activityScaledCol.
|
|
60
|
+
const activityScaledData = activityScaledCol.toList();
|
|
53
61
|
for (const position of positions) {
|
|
54
62
|
const posCol = table.getCol(position);
|
|
55
63
|
const aarList = selectionObject[position];
|
|
64
|
+
if (aarList.length === 0)
|
|
65
|
+
continue;
|
|
66
|
+
|
|
56
67
|
aarStr = `${position}: {${aarList.join(', ')}}`;
|
|
57
68
|
|
|
58
69
|
const mask = DG.BitSet.create(rowCount, (i) => aarList.includes(posCol.get(i)));
|
|
@@ -80,7 +91,7 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
otherStr = otherConst;
|
|
83
|
-
const activityScaledData = activityScaledCol.
|
|
94
|
+
const activityScaledData = activityScaledCol.toList();
|
|
84
95
|
for (const aar of aars) {
|
|
85
96
|
const posList = reversedSelectionObject[aar];
|
|
86
97
|
aarStr = `${aar}: {${posList.join(', ')}}`;
|
|
@@ -112,14 +123,18 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
112
123
|
otherStr = otherConst;
|
|
113
124
|
} else if (positionsLen) {
|
|
114
125
|
aarStr = '';
|
|
115
|
-
for (const position of positions)
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
for (const position of positions) {
|
|
127
|
+
const aarList = selectionObject[position];
|
|
128
|
+
if (aarList.length !== 0)
|
|
129
|
+
aarStr += `${position}: {${aarList.join(', ')}}; `;
|
|
130
|
+
}
|
|
131
|
+
if (clustersObject.length !== 0)
|
|
132
|
+
aarStr += `Clusters: ${clustersObject.join(', ')}`;
|
|
118
133
|
otherStr = otherConst;
|
|
119
134
|
}
|
|
120
135
|
|
|
121
136
|
const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
|
|
122
|
-
const stats = getStats(activityScaledCol.
|
|
137
|
+
const stats = getStats(activityScaledCol.toList(), table.selection);
|
|
123
138
|
const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr);
|
|
124
139
|
$(distributionRoot).addClass('d4-flex-col');
|
|
125
140
|
|
|
@@ -130,9 +145,9 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
130
145
|
};
|
|
131
146
|
|
|
132
147
|
const setDefaultProperties = (input: DG.InputBase): void => {
|
|
133
|
-
input.enabled =
|
|
148
|
+
input.enabled = !isMutationCliffsSelectionEmpty;
|
|
134
149
|
$(input.root).find('.ui-input-editor').css('margin', '0px');
|
|
135
|
-
$(input.root).find('.ui-input-description').css('padding', '0px');
|
|
150
|
+
$(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
|
|
136
151
|
};
|
|
137
152
|
|
|
138
153
|
const splitByPosition = ui.boolInput('', model.splitByPos, updateDistributionHost);
|
|
@@ -7,7 +7,7 @@ import {getSeparator} from '../utils/misc';
|
|
|
7
7
|
|
|
8
8
|
export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
|
|
9
9
|
const substInfo = model.substitutionsInfo;
|
|
10
|
-
const currentCell = model.
|
|
10
|
+
const currentCell = model.mutationCliffsSelection;
|
|
11
11
|
const positions = Object.keys(currentCell);
|
|
12
12
|
|
|
13
13
|
if (!positions.length)
|
|
@@ -16,7 +16,8 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
|
|
|
16
16
|
const substitutionsArray: string[] = [];
|
|
17
17
|
const deltaArray: number[] = [];
|
|
18
18
|
const substitutedToArray: string[] = [];
|
|
19
|
-
const alignedSeqCol = table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
|
|
19
|
+
// const alignedSeqCol = table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
|
|
20
|
+
const alignedSeqCol = table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
|
|
20
21
|
const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
21
22
|
const seenIndexes = new Map<number, number[]>();
|
|
22
23
|
|
|
@@ -12,10 +12,10 @@ import {scaleActivity} from '../utils/misc';
|
|
|
12
12
|
|
|
13
13
|
/** Peptide analysis widget.
|
|
14
14
|
*
|
|
15
|
-
* @param {DG.DataFrame}
|
|
15
|
+
* @param {DG.DataFrame} df Working table
|
|
16
16
|
* @param {DG.Column} col Aligned sequence column
|
|
17
17
|
* @return {Promise<DG.Widget>} Widget containing peptide analysis */
|
|
18
|
-
export async function analyzePeptidesWidget(
|
|
18
|
+
export async function analyzePeptidesWidget(df: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
|
|
19
19
|
if (!col.tags['aligned']?.includes('MSA') && col.tags[DG.TAGS.UNITS].toLowerCase() != 'helm')
|
|
20
20
|
return new DG.Widget(ui.divText('Peptides analysis only works with aligned sequences'));
|
|
21
21
|
|
|
@@ -30,19 +30,27 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
|
|
|
30
30
|
let tempCol = null;
|
|
31
31
|
let scaledDf: DG.DataFrame;
|
|
32
32
|
let newScaledColName: string;
|
|
33
|
+
let scalingFormula: (x: number) => number;
|
|
33
34
|
|
|
34
|
-
for (const column of
|
|
35
|
+
for (const column of df.columns.numerical)
|
|
35
36
|
tempCol = column.type === DG.TYPE.FLOAT ? column : null;
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
+
const defaultActivityColumn: DG.Column<number> | null = df.col('activity') || df.col('IC50') || tempCol;
|
|
38
39
|
const histogramHost = ui.div([], {id: 'pep-hist-host'});
|
|
39
40
|
|
|
41
|
+
const indexes: number[] = [];
|
|
42
|
+
const f = df.filter;
|
|
43
|
+
df.onFilterChanged.subscribe(() => {
|
|
44
|
+
for (let i = 0; i < f.length; ++i) {
|
|
45
|
+
if (f.get(i))
|
|
46
|
+
indexes.push(i);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
40
49
|
const activityScalingMethod = ui.choiceInput(
|
|
41
50
|
'Scaling', 'none', ['none', 'lg', '-lg'],
|
|
42
51
|
async (currentMethod: string): Promise<void> => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
[scaledDf, newScaledColName] = scaleActivity(currentMethod, currentDf, currentActivityCol, true);
|
|
52
|
+
[scaledDf, scalingFormula, newScaledColName] =
|
|
53
|
+
scaleActivity(currentMethod, activityColumnChoice.value!, indexes.length !== 0 ? indexes : undefined);
|
|
46
54
|
|
|
47
55
|
const hist = scaledDf.plot.histogram({
|
|
48
56
|
filteringEnabled: false,
|
|
@@ -60,21 +68,23 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
|
|
|
60
68
|
|
|
61
69
|
const activityScalingMethodState = (_: any): void => {
|
|
62
70
|
activityScalingMethod.enabled = (activityColumnChoice.value ?? false) &&
|
|
63
|
-
DG.Stats.fromColumn(activityColumnChoice.value!,
|
|
71
|
+
DG.Stats.fromColumn(activityColumnChoice.value!, df.filter).min > 0;
|
|
64
72
|
activityScalingMethod.fireChanged();
|
|
65
73
|
};
|
|
66
|
-
const activityColumnChoice = ui.columnInput('Activity',
|
|
74
|
+
const activityColumnChoice = ui.columnInput('Activity', df, defaultActivityColumn, activityScalingMethodState);
|
|
75
|
+
const clustersColumnChoice = ui.columnInput('Clusters', df, null);
|
|
67
76
|
activityColumnChoice.fireChanged();
|
|
68
77
|
activityScalingMethod.fireChanged();
|
|
69
78
|
|
|
70
|
-
const inputsList = [activityColumnChoice, activityScalingMethod];
|
|
79
|
+
const inputsList = [activityColumnChoice, activityScalingMethod, clustersColumnChoice];
|
|
71
80
|
|
|
72
81
|
const startBtn = ui.button('Launch SAR', async () => {
|
|
73
|
-
await startAnalysis(activityColumnChoice.value, col,
|
|
82
|
+
await startAnalysis(activityColumnChoice.value, col, clustersColumnChoice.value, df, scalingFormula,
|
|
83
|
+
newScaledColName, activityScalingMethod.value ?? 'none', indexes);
|
|
74
84
|
});
|
|
75
85
|
startBtn.style.alignSelf = 'center';
|
|
76
86
|
|
|
77
|
-
const viewer = await
|
|
87
|
+
const viewer = await df.plot.fromType('WebLogo') as WebLogo;
|
|
78
88
|
viewer.root.style.setProperty('height', '130px');
|
|
79
89
|
const logoHost = ui.div();
|
|
80
90
|
$(logoHost).empty().append(viewer.root);
|
|
@@ -85,38 +95,56 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
|
|
|
85
95
|
ui.splitH([
|
|
86
96
|
ui.splitV([ui.inputs(inputsList), startBtn]),
|
|
87
97
|
histogramHost,
|
|
88
|
-
], {style: {height: '
|
|
98
|
+
], {style: {height: '215px'}}),
|
|
89
99
|
]),
|
|
90
100
|
);
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
export async function startAnalysis(
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
export async function startAnalysis(activityColumn: DG.Column<number> | null, peptidesCol: DG.Column<string>,
|
|
104
|
+
clustersColumn: DG.Column | null, currentDf: DG.DataFrame, scaleNum: (x: number) => number, newScaledColName: string,
|
|
105
|
+
scaling: string, indexes: number[]): Promise<PeptidesModel | null> {
|
|
96
106
|
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
97
107
|
let model = null;
|
|
98
108
|
if (activityColumn?.type === DG.TYPE.FLOAT) {
|
|
99
|
-
const
|
|
100
|
-
|
|
109
|
+
const f = currentDf.filter;
|
|
101
110
|
//prepare new DF
|
|
102
|
-
const newDf =
|
|
103
|
-
const
|
|
104
|
-
activityCol.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
const newDf = DG.DataFrame.create(f.trueCount);
|
|
112
|
+
const getIndex = indexes.length !== 0 ? (i: number) : number => indexes[i] : (i: number): number => i;
|
|
113
|
+
let activityCol: DG.Column<number> | null = null;
|
|
114
|
+
for (const col of currentDf.columns.toList()) {
|
|
115
|
+
let virtualCol: DG.Column<any>;
|
|
116
|
+
if (col === activityColumn) {
|
|
117
|
+
virtualCol = newDf.columns.addNewVirtual(
|
|
118
|
+
C.COLUMNS_NAMES.ACTIVITY, (i) => activityColumn.get(getIndex(i)!), DG.TYPE.FLOAT);
|
|
119
|
+
activityCol = virtualCol;
|
|
120
|
+
} else if (col === peptidesCol) {
|
|
121
|
+
virtualCol = newDf.columns.addNewVirtual(
|
|
122
|
+
C.COLUMNS_NAMES.MACROMOLECULE, (i) => peptidesCol.get(getIndex(i)!), DG.TYPE.STRING);
|
|
123
|
+
} else
|
|
124
|
+
virtualCol = newDf.columns.addNewVirtual(col.name, (i) => col.get(getIndex(i)!), col.type as DG.TYPE);
|
|
125
|
+
virtualCol.setTag(C.TAGS.VISIBLE, '0');
|
|
126
|
+
}
|
|
127
|
+
activityCol!.semType = C.SEM_TYPES.ACTIVITY;
|
|
128
|
+
const activityScaledCol = newDf.columns.addNewVirtual(C.COLUMNS_NAMES.ACTIVITY_SCALED, (i) => {
|
|
129
|
+
const val = activityCol!.get(getIndex(i)!);
|
|
130
|
+
return val ? scaleNum(val) : val;
|
|
131
|
+
}, DG.TYPE.FLOAT);
|
|
108
132
|
activityScaledCol.semType = C.SEM_TYPES.ACTIVITY_SCALED;
|
|
109
|
-
newDf.columns.add(activityScaledCol);
|
|
110
133
|
newDf.name = 'Peptides analysis';
|
|
111
134
|
newDf.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newScaledColName;
|
|
135
|
+
if (clustersColumn) {
|
|
136
|
+
newDf.getCol(clustersColumn.name).name = C.COLUMNS_NAMES.CLUSTERS;
|
|
137
|
+
newDf.tags[C.TAGS.CLUSTERS] = C.COLUMNS_NAMES.CLUSTERS;
|
|
138
|
+
}
|
|
112
139
|
// newDf.tags[C.PEPTIDES_ANALYSIS] = 'true';
|
|
140
|
+
newDf.tags['scaling'] = scaling;
|
|
113
141
|
|
|
114
142
|
let monomerType = 'HELM_AA';
|
|
115
|
-
if (
|
|
116
|
-
const sampleSeq =
|
|
143
|
+
if (peptidesCol.getTag(DG.TAGS.UNITS).toLowerCase() == 'helm') {
|
|
144
|
+
const sampleSeq = peptidesCol.get(0)!;
|
|
117
145
|
monomerType = sampleSeq.startsWith('PEPTIDE') ? 'HELM_AA' : 'HELM_BASE';
|
|
118
146
|
} else {
|
|
119
|
-
const alphabet =
|
|
147
|
+
const alphabet = peptidesCol.tags[C.TAGS.ALPHABET];
|
|
120
148
|
monomerType = alphabet == 'DNA' || alphabet == 'RNA' ? 'HELM_BASE' : 'HELM_AA';
|
|
121
149
|
}
|
|
122
150
|
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=8408d9b6ee67. Commit ca232121.</title><style type="text/css">html,
|
|
2
|
+
body {
|
|
3
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
4
|
+
font-size: 1rem;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
|
+
color: #333;
|
|
8
|
+
}
|
|
9
|
+
body {
|
|
10
|
+
padding: 2rem 1rem;
|
|
11
|
+
font-size: 0.85rem;
|
|
12
|
+
}
|
|
13
|
+
#jesthtml-content {
|
|
14
|
+
margin: 0 auto;
|
|
15
|
+
max-width: 70rem;
|
|
16
|
+
}
|
|
17
|
+
header {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
}
|
|
21
|
+
#title {
|
|
22
|
+
margin: 0;
|
|
23
|
+
flex-grow: 1;
|
|
24
|
+
}
|
|
25
|
+
#logo {
|
|
26
|
+
height: 4rem;
|
|
27
|
+
}
|
|
28
|
+
#timestamp {
|
|
29
|
+
color: #777;
|
|
30
|
+
margin-top: 0.5rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** SUMMARY */
|
|
34
|
+
#summary {
|
|
35
|
+
color: #333;
|
|
36
|
+
margin: 2rem 0;
|
|
37
|
+
display: flex;
|
|
38
|
+
font-family: monospace;
|
|
39
|
+
font-size: 1rem;
|
|
40
|
+
}
|
|
41
|
+
#summary > div {
|
|
42
|
+
margin-right: 2rem;
|
|
43
|
+
background: #eee;
|
|
44
|
+
padding: 1rem;
|
|
45
|
+
min-width: 15rem;
|
|
46
|
+
}
|
|
47
|
+
#summary > div:last-child {
|
|
48
|
+
margin-right: 0;
|
|
49
|
+
}
|
|
50
|
+
@media only screen and (max-width: 720px) {
|
|
51
|
+
#summary {
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
}
|
|
54
|
+
#summary > div {
|
|
55
|
+
margin-right: 0;
|
|
56
|
+
margin-top: 2rem;
|
|
57
|
+
}
|
|
58
|
+
#summary > div:first-child {
|
|
59
|
+
margin-top: 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.summary-total {
|
|
64
|
+
font-weight: bold;
|
|
65
|
+
margin-bottom: 0.5rem;
|
|
66
|
+
}
|
|
67
|
+
.summary-passed {
|
|
68
|
+
color: #4f8a10;
|
|
69
|
+
border-left: 0.4rem solid #4f8a10;
|
|
70
|
+
padding-left: 0.5rem;
|
|
71
|
+
}
|
|
72
|
+
.summary-failed,
|
|
73
|
+
.summary-obsolete-snapshots {
|
|
74
|
+
color: #d8000c;
|
|
75
|
+
border-left: 0.4rem solid #d8000c;
|
|
76
|
+
padding-left: 0.5rem;
|
|
77
|
+
}
|
|
78
|
+
.summary-pending {
|
|
79
|
+
color: #9f6000;
|
|
80
|
+
border-left: 0.4rem solid #9f6000;
|
|
81
|
+
padding-left: 0.5rem;
|
|
82
|
+
}
|
|
83
|
+
.summary-empty {
|
|
84
|
+
color: #999;
|
|
85
|
+
border-left: 0.4rem solid #999;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.test-result {
|
|
89
|
+
padding: 1rem;
|
|
90
|
+
margin-bottom: 0.25rem;
|
|
91
|
+
}
|
|
92
|
+
.test-result:last-child {
|
|
93
|
+
border: 0;
|
|
94
|
+
}
|
|
95
|
+
.test-result.passed {
|
|
96
|
+
background-color: #dff2bf;
|
|
97
|
+
color: #4f8a10;
|
|
98
|
+
}
|
|
99
|
+
.test-result.failed {
|
|
100
|
+
background-color: #ffbaba;
|
|
101
|
+
color: #d8000c;
|
|
102
|
+
}
|
|
103
|
+
.test-result.pending {
|
|
104
|
+
background-color: #ffdf61;
|
|
105
|
+
color: #9f6000;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.test-info {
|
|
109
|
+
display: flex;
|
|
110
|
+
justify-content: space-between;
|
|
111
|
+
}
|
|
112
|
+
.test-suitename {
|
|
113
|
+
width: 20%;
|
|
114
|
+
text-align: left;
|
|
115
|
+
font-weight: bold;
|
|
116
|
+
word-break: break-word;
|
|
117
|
+
}
|
|
118
|
+
.test-title {
|
|
119
|
+
width: 40%;
|
|
120
|
+
text-align: left;
|
|
121
|
+
font-style: italic;
|
|
122
|
+
}
|
|
123
|
+
.test-status {
|
|
124
|
+
width: 20%;
|
|
125
|
+
text-align: right;
|
|
126
|
+
}
|
|
127
|
+
.test-duration {
|
|
128
|
+
width: 10%;
|
|
129
|
+
text-align: right;
|
|
130
|
+
font-size: 0.75rem;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.failureMessages {
|
|
134
|
+
padding: 0 1rem;
|
|
135
|
+
margin-top: 1rem;
|
|
136
|
+
border-top: 1px dashed #d8000c;
|
|
137
|
+
}
|
|
138
|
+
.failureMessages.suiteFailure {
|
|
139
|
+
border-top: none;
|
|
140
|
+
}
|
|
141
|
+
.failureMsg {
|
|
142
|
+
white-space: pre-wrap;
|
|
143
|
+
white-space: -moz-pre-wrap;
|
|
144
|
+
white-space: -pre-wrap;
|
|
145
|
+
white-space: -o-pre-wrap;
|
|
146
|
+
word-wrap: break-word;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.suite-container {
|
|
150
|
+
margin-bottom: 2rem;
|
|
151
|
+
}
|
|
152
|
+
.suite-info {
|
|
153
|
+
padding: 1rem;
|
|
154
|
+
background-color: #eee;
|
|
155
|
+
color: #777;
|
|
156
|
+
display: flex;
|
|
157
|
+
align-items: center;
|
|
158
|
+
margin-bottom: 0.25rem;
|
|
159
|
+
}
|
|
160
|
+
.suite-info .suite-path {
|
|
161
|
+
word-break: break-all;
|
|
162
|
+
flex-grow: 1;
|
|
163
|
+
font-family: monospace;
|
|
164
|
+
font-size: 1rem;
|
|
165
|
+
}
|
|
166
|
+
.suite-info .suite-time {
|
|
167
|
+
margin-left: 0.5rem;
|
|
168
|
+
padding: 0.2rem 0.3rem;
|
|
169
|
+
font-size: 0.75rem;
|
|
170
|
+
}
|
|
171
|
+
.suite-info .suite-time.warn {
|
|
172
|
+
background-color: #d8000c;
|
|
173
|
+
color: #fff;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* CONSOLE LOGS */
|
|
177
|
+
.suite-consolelog {
|
|
178
|
+
margin-bottom: 0.25rem;
|
|
179
|
+
padding: 1rem;
|
|
180
|
+
background-color: #efefef;
|
|
181
|
+
}
|
|
182
|
+
.suite-consolelog-header {
|
|
183
|
+
font-weight: bold;
|
|
184
|
+
}
|
|
185
|
+
.suite-consolelog-item {
|
|
186
|
+
padding: 0.5rem;
|
|
187
|
+
}
|
|
188
|
+
.suite-consolelog-item pre {
|
|
189
|
+
margin: 0.5rem 0;
|
|
190
|
+
white-space: pre-wrap;
|
|
191
|
+
white-space: -moz-pre-wrap;
|
|
192
|
+
white-space: -pre-wrap;
|
|
193
|
+
white-space: -o-pre-wrap;
|
|
194
|
+
word-wrap: break-word;
|
|
195
|
+
}
|
|
196
|
+
.suite-consolelog-item-origin {
|
|
197
|
+
color: #777;
|
|
198
|
+
font-weight: bold;
|
|
199
|
+
}
|
|
200
|
+
.suite-consolelog-item-message {
|
|
201
|
+
color: #000;
|
|
202
|
+
font-size: 1rem;
|
|
203
|
+
padding: 0 0.5rem;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* OBSOLETE SNAPSHOTS */
|
|
207
|
+
.suite-obsolete-snapshots {
|
|
208
|
+
margin-bottom: 0.25rem;
|
|
209
|
+
padding: 1rem;
|
|
210
|
+
background-color: #ffbaba;
|
|
211
|
+
color: #d8000c;
|
|
212
|
+
}
|
|
213
|
+
.suite-obsolete-snapshots-header {
|
|
214
|
+
font-weight: bold;
|
|
215
|
+
}
|
|
216
|
+
.suite-obsolete-snapshots-item {
|
|
217
|
+
padding: 0.5rem;
|
|
218
|
+
}
|
|
219
|
+
.suite-obsolete-snapshots-item pre {
|
|
220
|
+
margin: 0.5rem 0;
|
|
221
|
+
white-space: pre-wrap;
|
|
222
|
+
white-space: -moz-pre-wrap;
|
|
223
|
+
white-space: -pre-wrap;
|
|
224
|
+
white-space: -o-pre-wrap;
|
|
225
|
+
word-wrap: break-word;
|
|
226
|
+
}
|
|
227
|
+
.suite-obsolete-snapshots-item-message {
|
|
228
|
+
color: #000;
|
|
229
|
+
font-size: 1rem;
|
|
230
|
+
padding: 0 0.5rem;
|
|
231
|
+
}
|
|
232
|
+
</style></head><body><div id="jesthtml-content"><header><h1 id="title">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=8408d9b6ee67. Commit ca232121.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-10-11 15:08:32</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts</div><div class="suite-time warn">127.821s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">112.749s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Evaluation failed: TypeError: Cannot read properties of null (reading 'get')
|
|
233
|
+
at __puppeteer_evaluation_script__:17:71
|
|
234
|
+
at ExecutionContext._evaluateInternal (/home/runner/work/public/public/packages/Peptides/node_modules/puppeteer/src/common/ExecutionContext.ts:273:13)
|
|
235
|
+
at processTicksAndRejections (internal/process/task_queues.js:97:5)
|
|
236
|
+
at ExecutionContext.evaluate (/home/runner/work/public/public/packages/Peptides/node_modules/puppeteer/src/common/ExecutionContext.ts:140:12)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.<anonymous> (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:62:11)
|
|
237
|
+
at Generator.next (<anonymous>)
|
|
238
|
+
at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:28:58)
|
|
239
|
+
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:40:11
|
|
240
|
+
at Generator.next (<anonymous>)
|
|
241
|
+
at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:34:71
|
|
242
|
+
at new Promise (<anonymous>)
|
|
243
|
+
at Object.<anonymous>.__awaiter (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:30:12)
|
|
244
|
+
at Object.<anonymous> (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:38:23)
|
|
245
|
+
at Promise.then.completed (/home/runner/work/public/public/packages/Peptides/node_modules/jest-circus/build/utils.js:391:28)
|
|
246
|
+
at new Promise (<anonymous>)</pre><pre class="suite-consolelog-item-message">Testing Peptides package</pre></div></div></div></div></body></html>
|
|
@@ -1,163 +0,0 @@
|
|
|
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
|
-
}
|