@datagrok/bio 2.4.47 → 2.4.49
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/css/composition-analysis.css +16 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/samples/sample_HELM.csv +1 -1
- package/package.json +3 -3
- package/src/calculations/monomerLevelMols.ts +2 -2
- package/src/package-test.ts +1 -0
- package/src/package.ts +9 -0
- package/src/tests/renderers-monomer-placer.ts +109 -0
- package/src/tests/renderers-test.ts +15 -6
- package/src/tests/utils/sequences-generators.ts +1 -10
- package/src/utils/cell-renderer.ts +160 -123
- package/src/utils/convert.ts +5 -1
- package/src/widgets/composition-analysis-widget.ts +62 -0
|
@@ -538,4 +538,4 @@ PEPTIDE1{aThr.hHis.Aca.Q.T.W.Q.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.Q.N.N.Phe_4Me}$$
|
|
|
538
538
|
PEPTIDE1{meI.hHis.Aca.Q.T.W.Q.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.Bmt.Phe_4Me}$$$$,1.3272504220357146
|
|
539
539
|
PEPTIDE1{meI.hHis.Aca.Q.T.W.Q.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.Thr_PO3H2.Phe_4Me}$$$$,2.25061208046269
|
|
540
540
|
PEPTIDE1{meI.hHis.Aca.Q.T.W.Q.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.dV.Phe_4Me}$$$$,4.2426827257450315
|
|
541
|
-
PEPTIDE1{meI.hHis.Hcy.Q.T.W.Q.Phe_4NH2.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.N.meK}$$$$,2.9379590568765788
|
|
541
|
+
PEPTIDE1{meI.hHis.Hcy.Q.T.W.Q.Phe_4NH2.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.N.meK}$$$$,2.9379590568765788
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.4.
|
|
8
|
+
"version": "2.4.49",
|
|
9
9
|
"description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@biowasm/aioli": "^3.1.0",
|
|
25
|
-
"@datagrok-libraries/bio": "^5.32.
|
|
25
|
+
"@datagrok-libraries/bio": "^5.32.7",
|
|
26
26
|
"@datagrok-libraries/chem-meta": "^1.0.1",
|
|
27
27
|
"@datagrok-libraries/ml": "^6.3.39",
|
|
28
28
|
"@datagrok-libraries/tutorials": "^1.3.2",
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"fastest-levenshtein": "^1.0.16",
|
|
35
35
|
"openchemlib": "6.0.1",
|
|
36
36
|
"rxjs": "^6.5.5",
|
|
37
|
-
"source-map-loader": "^4.0.1",
|
|
38
37
|
"style-loader": "^3.3.1",
|
|
39
38
|
"wu": "latest"
|
|
40
39
|
},
|
|
@@ -45,6 +44,7 @@
|
|
|
45
44
|
"@typescript-eslint/parser": "latest",
|
|
46
45
|
"eslint": "latest",
|
|
47
46
|
"eslint-config-google": "latest",
|
|
47
|
+
"source-map-loader": "^4.0.1",
|
|
48
48
|
"ts-loader": "^9.2.5",
|
|
49
49
|
"typescript": "^5.0.4",
|
|
50
50
|
"webpack": "^5.76.0",
|
|
@@ -13,7 +13,7 @@ export async function getMonomericMols(
|
|
|
13
13
|
const uh = UnitsHandler.getOrCreate(mcol);
|
|
14
14
|
let molV3000Array;
|
|
15
15
|
monomersDict ??= new Map();
|
|
16
|
-
const monomers = uh.
|
|
16
|
+
const monomers = uh.isHelm() ?
|
|
17
17
|
getHelmMonomers(mcol) : Object.keys(uh.stats.freq).filter((it) => it !== '');
|
|
18
18
|
|
|
19
19
|
for (let i = 0; i < monomers.length; i++) {
|
|
@@ -21,7 +21,7 @@ export async function getMonomericMols(
|
|
|
21
21
|
monomersDict.set(monomers[i], `${monomersDict.size + 1}`);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (uh.
|
|
24
|
+
if (uh.isHelm()) {
|
|
25
25
|
molV3000Array = await grok.functions.call('HELM:getMolFiles', {col: mcol});
|
|
26
26
|
molV3000Array = changeV2000ToV3000(molV3000Array, monomersDict, pattern);
|
|
27
27
|
} else {
|
package/src/package-test.ts
CHANGED
|
@@ -13,6 +13,7 @@ import './tests/splitters-test'; //Unhandled exceptions.exceptions : Cannot read
|
|
|
13
13
|
|
|
14
14
|
import './tests/monomer-libraries-tests';
|
|
15
15
|
import './tests/renderers-test';
|
|
16
|
+
import './tests/renderers-monomer-placer';
|
|
16
17
|
import './tests/converters-test';
|
|
17
18
|
import './tests/fasta-handler-test';
|
|
18
19
|
import './tests/fasta-export-tests';
|
package/src/package.ts
CHANGED
|
@@ -57,6 +57,7 @@ import {BioPackage, BioPackageProperties} from './package-types';
|
|
|
57
57
|
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
58
58
|
import {ObjectPropertyBag} from 'datagrok-api/dg';
|
|
59
59
|
import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
|
|
60
|
+
import {getCompositionAnalysisWidget} from './widgets/composition-analysis-widget';
|
|
60
61
|
|
|
61
62
|
export const _package = new BioPackage();
|
|
62
63
|
|
|
@@ -218,6 +219,14 @@ export function macroMolColumnPropertyPanel(molColumn: DG.Column): DG.Widget {
|
|
|
218
219
|
return getMacromoleculeColumnPropertyPanel(molColumn);
|
|
219
220
|
}
|
|
220
221
|
|
|
222
|
+
//name: Composition analysis
|
|
223
|
+
//tags: panel, bio, widgets
|
|
224
|
+
//input: semantic_value sequence { semType: Macromolecule }
|
|
225
|
+
//output: widget result
|
|
226
|
+
export function compositionAnalysisWidget(sequence: DG.SemanticValue): DG.Widget {
|
|
227
|
+
return getCompositionAnalysisWidget(sequence);
|
|
228
|
+
}
|
|
229
|
+
|
|
221
230
|
//name: separatorSequenceCellRenderer
|
|
222
231
|
//tags: cellRenderer
|
|
223
232
|
//meta.cellType: sequence
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
4
|
+
|
|
5
|
+
import {_package} from '../package-test';
|
|
6
|
+
import {after, before, category, delay, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
7
|
+
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
8
|
+
import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
9
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
10
|
+
|
|
11
|
+
category('renderers: monomerPlacer', () => {
|
|
12
|
+
const tests = {
|
|
13
|
+
splitter: {
|
|
14
|
+
/**
|
|
15
|
+
0 = Array(10) [0, 26, 45, 71, 97, 123, 142, 161, 187, 213],
|
|
16
|
+
1 = Array(9) [0, 26, 52, 78, 104, 130, 156, 182, 208],
|
|
17
|
+
2 = Array(8) [0, 26, 45, 71, 97, 123, 149, 175],
|
|
18
|
+
* */
|
|
19
|
+
csv: 'id,seq\n' +
|
|
20
|
+
'id1,m1-M-m3-mon4-mon5-N-T-MON8-N9\n' + //Array(10) [0, 26, 52, 78, 104, 130, 156, 175, 201, 227]
|
|
21
|
+
'id2,m1-mon2-m3-mon4-mon5-Num-MON8-N9\n' + //
|
|
22
|
+
'id3,mon1-M-mon3-mon4-mon5-MON8-N9\n', //
|
|
23
|
+
testList: [
|
|
24
|
+
{src: {row: 0, x: -1}, tgt: {pos: null}},
|
|
25
|
+
{src: {row: 1, x: 0}, tgt: {pos: 0}},
|
|
26
|
+
{src: {row: 1, x: 1}, tgt: {pos: 0}},
|
|
27
|
+
{src: {row: 1, x: 26}, tgt: {pos: 1}},
|
|
28
|
+
{src: {row: 1, x: 170}, tgt: {pos: 6}},
|
|
29
|
+
{src: {row: 1, x: 208}, tgt: {pos: null}},
|
|
30
|
+
{src: {row: 2, x: 170}, tgt: {pos: 6}},
|
|
31
|
+
{src: {row: 2, x: 175}, tgt: {pos: null}},
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
splitterMsa: {
|
|
35
|
+
/** For charWidth=7 and sepWidth=12, MSA
|
|
36
|
+
* Array(10) [0, 26, 52, 78, 104, 130, 156, 175, 201, 227]
|
|
37
|
+
*/
|
|
38
|
+
csv: 'id,seq\n' +
|
|
39
|
+
'id1,m1-M-m3-mon4-mon5-N-T-MON8-N9\n' + //Array(10) [0, 26, 52, 78, 104, 130, 156, 175, 201, 227]
|
|
40
|
+
'id2,m1-mon2-m3-mon4-mon5-Num--MON8-N9\n' + //
|
|
41
|
+
'id3,mon1-M-mon3-mon4-mon5---MON8-N9\n', //
|
|
42
|
+
testList: [
|
|
43
|
+
{src: {row: 0, x: -1}, tgt: {pos: null}},
|
|
44
|
+
{src: {row: 1, x: 0}, tgt: {pos: 0}},
|
|
45
|
+
{src: {row: 1, x: 1}, tgt: {pos: 0}},
|
|
46
|
+
{src: {row: 1, x: 26}, tgt: {pos: 1}},
|
|
47
|
+
{src: {row: 1, x: 170}, tgt: {pos: 6}},
|
|
48
|
+
{src: {row: 1, x: 227}, tgt: {pos: null}},
|
|
49
|
+
{src: {row: 2, x: 220}, tgt: {pos: 8}},
|
|
50
|
+
{src: {row: 2, x: 227}, tgt: {pos: null}},
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
fastaMsa: {
|
|
54
|
+
/** For charWidth=7 and sepWidth=12, MSA
|
|
55
|
+
* Array(10) [0, 19, 38, 57, 76, 95, 114, 133, 152, 171]
|
|
56
|
+
*/
|
|
57
|
+
csv: `id,seq
|
|
58
|
+
id1,QQYNIYPLT
|
|
59
|
+
id2,QQWSSFPYT
|
|
60
|
+
id3,QHIRE--LT
|
|
61
|
+
`,
|
|
62
|
+
testList: [
|
|
63
|
+
{src: {row: 1, x: -1}, tgt: {pos: null}},
|
|
64
|
+
{src: {row: 1, x: 0}, tgt: {pos: 0}},
|
|
65
|
+
{src: {row: 1, x: 1}, tgt: {pos: 0}},
|
|
66
|
+
{src: {row: 1, x: 19}, tgt: {pos: 1}},
|
|
67
|
+
{src: {row: 1, x: 170}, tgt: {pos: 8}},
|
|
68
|
+
{src: {row: 1, x: 171}, tgt: {pos: null}},
|
|
69
|
+
{src: {row: 2, x: 170}, tgt: {pos: 8}},
|
|
70
|
+
{src: {row: 2, x: 171}, tgt: {pos: null}},
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
for (const [testName, testData] of Object.entries(tests)) {
|
|
76
|
+
test(`getPosition_${testName}`, async () => {
|
|
77
|
+
const df: DG.DataFrame = DG.DataFrame.fromCsv(testData.csv);
|
|
78
|
+
await grok.data.detectSemanticTypes(df);
|
|
79
|
+
const seqCol: DG.Column = df.getCol('seq');
|
|
80
|
+
|
|
81
|
+
const monLength: number = 1;
|
|
82
|
+
const charWidth: number = 7;
|
|
83
|
+
const sepWidth: number = 12;
|
|
84
|
+
const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, () => {
|
|
85
|
+
const uh = UnitsHandler.getOrCreate(seqCol);
|
|
86
|
+
return {
|
|
87
|
+
unitsHandler: uh,
|
|
88
|
+
monomerCharWidth: charWidth,
|
|
89
|
+
separatorWidth: sepWidth,
|
|
90
|
+
monomerToShort: monomerToShort,
|
|
91
|
+
monomerLengthLimit: monLength,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const testList = testData.testList;
|
|
96
|
+
|
|
97
|
+
const errorList: string[] = [];
|
|
98
|
+
for (const test of testList) {
|
|
99
|
+
const res = {pos: colTemp.getPosition(test.src.row, test.src.x)};
|
|
100
|
+
if (test.tgt.pos != res.pos) {
|
|
101
|
+
errorList.push(`Test src ${JSON.stringify(test.src)} expected tgt ${JSON.stringify(test.tgt)},` +
|
|
102
|
+
` but get ${JSON.stringify({res})}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (errorList.length > 0)
|
|
106
|
+
throw new Error('Test failed error(s):\n' + errorList.join(', n'));
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
});
|
|
@@ -108,8 +108,11 @@ category('renderers', () => {
|
|
|
108
108
|
async function _rendererMacromoleculeDifference() {
|
|
109
109
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
110
110
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
111
|
-
seqDiffCol.
|
|
112
|
-
seqDiffCol.
|
|
111
|
+
seqDiffCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
112
|
+
seqDiffCol.setTag(bioTAGS.separator, '/');
|
|
113
|
+
seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
|
|
114
|
+
seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
|
|
115
|
+
seqDiffCol.setTag(bioTAGS.alphabetIsMultichar, 'true');
|
|
113
116
|
seqDiffCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
114
117
|
const df = DG.DataFrame.fromColumns([seqDiffCol]);
|
|
115
118
|
|
|
@@ -195,8 +198,11 @@ category('renderers', () => {
|
|
|
195
198
|
/**/
|
|
196
199
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
197
200
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
198
|
-
seqDiffCol.
|
|
199
|
-
seqDiffCol.
|
|
201
|
+
seqDiffCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
202
|
+
seqDiffCol.setTag(bioTAGS.separator, '/');
|
|
203
|
+
seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
|
|
204
|
+
seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
|
|
205
|
+
seqDiffCol.setTag(bioTAGS.alphabetIsMultichar, 'true');
|
|
200
206
|
seqDiffCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
201
207
|
const df = DG.DataFrame.fromColumns([seqDiffCol]);
|
|
202
208
|
const tv = grok.shell.addTableView(df);
|
|
@@ -217,8 +223,11 @@ category('renderers', () => {
|
|
|
217
223
|
async function _setRendererManually() {
|
|
218
224
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
219
225
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
220
|
-
seqDiffCol.
|
|
221
|
-
seqDiffCol.
|
|
226
|
+
seqDiffCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
227
|
+
seqDiffCol.setTag(bioTAGS.separator, '/');
|
|
228
|
+
seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
|
|
229
|
+
seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
|
|
230
|
+
seqDiffCol.setTag(bioTAGS.alphabetIsMultichar, 'true');
|
|
222
231
|
seqDiffCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
223
232
|
const tgtCellRenderer = 'MacromoleculeDifference';
|
|
224
233
|
seqDiffCol.setTag(DG.TAGS.CELL_RENDERER, tgtCellRenderer);
|
|
@@ -23,21 +23,12 @@ export function generateLongSequence(): DG.Column[] {
|
|
|
23
23
|
return columns;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function setTagsMacromolecule(col: DG.Column) {
|
|
27
|
-
col.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
28
|
-
col.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
29
|
-
col.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
30
|
-
col.setTag(bioTAGS.alphabet, ALPHABET.UN);
|
|
31
|
-
col.setTag(bioTAGS.separator, '/');
|
|
32
|
-
return col;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
26
|
export function performanceTest(generateFunc: () => DG.Column[], testName: string) {
|
|
36
27
|
const columns = generateFunc();
|
|
37
28
|
const df: DG.DataFrame = DG.DataFrame.fromColumns(columns);
|
|
29
|
+
grok.data.detectSemanticTypes(df);
|
|
38
30
|
const startTime: number = Date.now();
|
|
39
31
|
const col: DG.Column = df.columns.byName('MSA');
|
|
40
|
-
setTagsMacromolecule(col);
|
|
41
32
|
grok.shell.addTableView(df);
|
|
42
33
|
|
|
43
34
|
const endTime: number = Date.now();
|
|
@@ -2,37 +2,45 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
|
|
5
|
+
import {_package, getBioLib} from '../package';
|
|
5
6
|
import {printLeftOrCentered, DrawStyle} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
7
|
+
import * as C from './constants';
|
|
8
|
+
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
6
9
|
import {
|
|
7
10
|
ALIGNMENT, ALPHABET,
|
|
8
11
|
getPaletteByType,
|
|
9
12
|
getSplitter,
|
|
13
|
+
getSplitterForColumn,
|
|
10
14
|
monomerToShort,
|
|
15
|
+
MonomerToShortFunc,
|
|
11
16
|
NOTATION,
|
|
12
17
|
SplitterFunc,
|
|
13
18
|
TAGS as bioTAGS,
|
|
14
19
|
} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
15
20
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
16
21
|
import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
|
|
22
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
17
23
|
import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
18
24
|
import {Tags as mmcrTags, Temps as mmcrTemps} from '../utils/cell-renderer-consts';
|
|
19
|
-
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
25
|
+
import { HELM_POLYMER_TYPE } from '@datagrok-libraries/bio/src/utils/const';
|
|
26
|
+
import { MonomerLib } from './monomer-lib';
|
|
27
|
+
import { IMonomerLib } from '@datagrok-libraries/bio/src/types';
|
|
22
28
|
|
|
23
29
|
const enum tempTAGS {
|
|
24
30
|
referenceSequence = 'reference-sequence',
|
|
25
31
|
currentWord = 'current-word',
|
|
26
32
|
monomerWidth = 'monomer-width',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
bioSeqCol = 'bio-seqCol',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const enum rndrTAGS {
|
|
37
|
+
calculatedCellRender = '.calculatedCellRender',
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
type TempType = { [tagName: string]: any };
|
|
33
41
|
|
|
34
42
|
const undefinedColor = 'rgb(100,100,100)';
|
|
35
|
-
const monomerToShortFunction:
|
|
43
|
+
const monomerToShortFunction: MonomerToShortFunc = monomerToShort;
|
|
36
44
|
|
|
37
45
|
function getUpdatedWidth(grid: DG.Grid | null, g: CanvasRenderingContext2D, x: number, w: number): number {
|
|
38
46
|
return grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
@@ -55,8 +63,9 @@ export function processSequence(subParts: string[]): [string[], boolean] {
|
|
|
55
63
|
return [text, simplified];
|
|
56
64
|
}
|
|
57
65
|
|
|
58
|
-
|
|
59
66
|
export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
67
|
+
private padding: number = 5;
|
|
68
|
+
|
|
60
69
|
get name(): string { return 'sequence'; }
|
|
61
70
|
|
|
62
71
|
get cellType(): string { return 'sequence'; }
|
|
@@ -72,39 +81,39 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
75
|
-
if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
// if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
|
|
85
|
+
// return;
|
|
86
|
+
|
|
87
|
+
const tableCol: DG.Column = gridCell.cell.column;
|
|
88
|
+
const tableColTemp: TempType = tableCol.temp;
|
|
89
|
+
const seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
|
|
90
|
+
if (!seqColTemp) return; // Can do nothing without precalculated data
|
|
91
|
+
|
|
92
|
+
const gridCellBounds: DG.Rect = gridCell.bounds;
|
|
93
|
+
// const value: any = gridCell.cell.value;
|
|
94
|
+
//
|
|
95
|
+
// const maxLengthWords: number[] = seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!);
|
|
96
|
+
// const maxLengthWordsSum: number[] = new Array<number>(maxLengthWords.length).fill(0);
|
|
97
|
+
// for (let posI: number = 1; posI < maxLengthWords.length; posI++)
|
|
98
|
+
// maxLengthWordsSum[posI] = maxLengthWordsSum[posI - 1] + maxLengthWords[posI];
|
|
99
|
+
// const maxIndex = maxLengthWords.length;
|
|
100
|
+
const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCellBounds.x);
|
|
101
|
+
const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX);
|
|
102
|
+
|
|
103
|
+
const seqMonList: string[] = seqColTemp.getSeqMonList(gridCell.tableRowIndex!);
|
|
104
|
+
if (left !== null && left < seqMonList.length) {
|
|
105
|
+
const monomerSymbol: string = seqMonList[left];
|
|
106
|
+
const tooltipElements: HTMLElement[] = [ui.div(monomerSymbol)];
|
|
107
|
+
const monomer = seqColTemp.getMonomer(monomerSymbol);
|
|
108
|
+
if(monomer) {
|
|
109
|
+
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
110
|
+
const monomerSVG = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
111
|
+
tooltipElements.push(monomerSVG);
|
|
100
112
|
}
|
|
113
|
+
ui.tooltip.show(ui.divV(tooltipElements), e.x + 16, e.y + 16);
|
|
114
|
+
} else {
|
|
115
|
+
ui.tooltip.hide();
|
|
101
116
|
}
|
|
102
|
-
left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
|
|
103
|
-
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
104
|
-
const splitterFunc: SplitterFunc = getSplitter('separator', separator);
|
|
105
|
-
const subParts: string[] = splitterFunc(gridCell.cell.value);
|
|
106
|
-
(((subParts[left]?.length ?? 0) > 0)) ?
|
|
107
|
-
ui.tooltip.show(ui.div(subParts[left]), e.x + 16, e.y + 16) : ui.tooltip.hide();
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
/**
|
|
@@ -120,102 +129,130 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
120
129
|
* @memberof AlignedSequenceCellRenderer
|
|
121
130
|
*/
|
|
122
131
|
render(
|
|
123
|
-
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
124
|
-
|
|
125
|
-
) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const paletteType = gridCell.cell.column.getTag(bioTAGS.alphabet);
|
|
129
|
-
const minDistanceRenderer = 50;
|
|
130
|
-
w = getUpdatedWidth(grid, g, x, w);
|
|
131
|
-
g.save();
|
|
132
|
-
g.beginPath();
|
|
133
|
-
g.rect(x, y, w, h);
|
|
134
|
-
g.clip();
|
|
135
|
-
g.font = '12px monospace';
|
|
136
|
-
g.textBaseline = 'top';
|
|
137
|
-
|
|
138
|
-
//TODO: can this be replaced/merged with splitSequence?
|
|
139
|
-
const units = gridCell.cell.column.getTag(DG.TAGS.UNITS);
|
|
140
|
-
const aligned: string = gridCell.cell.column.getTag(bioTAGS.aligned);
|
|
141
|
-
|
|
142
|
-
const palette = getPaletteByType(paletteType);
|
|
143
|
-
|
|
144
|
-
const separator = gridCell.cell.column.getTag(bioTAGS.separator) ?? '';
|
|
145
|
-
const splitLimit = w / 5;
|
|
146
|
-
const splitterFunc: SplitterFunc = getSplitter(units, separator, splitLimit);
|
|
132
|
+
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
|
|
133
|
+
cellStyle: DG.GridCellStyle
|
|
134
|
+
): void {
|
|
135
|
+
let gapRenderer = 5;
|
|
136
|
+
let maxLengthOfMonomer = 8;
|
|
147
137
|
|
|
148
138
|
// TODO: Store temp data to GridColumn
|
|
149
139
|
// Now the renderer requires data frame table Column underlying GridColumn
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
const tempCurrentWord: string | null = colTemp[tempTAGS.currentWord];
|
|
154
|
-
const tempMonomerWidth: string | null = colTemp[tempTAGS.monomerWidth];
|
|
155
|
-
const referenceSequence: string[] = splitterFunc(
|
|
156
|
-
((tempReferenceSequence != null) && (tempReferenceSequence != '')) ?
|
|
157
|
-
tempReferenceSequence : tempCurrentWord ?? '');
|
|
158
|
-
const monomerWidth: string = tempMonomerWidth ?? 'short';
|
|
159
|
-
|
|
160
|
-
let gapRenderer = 5;
|
|
161
|
-
let maxIndex = 0;
|
|
162
|
-
let maxLengthOfMonomer: number = 8;
|
|
140
|
+
const view = gridCell.grid.view;
|
|
141
|
+
const tableCol: DG.Column = gridCell.cell.column;
|
|
142
|
+
const tableColTemp: TempType = tableCol.temp;
|
|
163
143
|
|
|
144
|
+
// Cell renderer settings
|
|
145
|
+
const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
|
|
146
|
+
const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
|
|
164
147
|
if (monomerWidth === 'short') {
|
|
165
|
-
|
|
166
|
-
maxLengthOfMonomer = colTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.maxMonomerLength;
|
|
148
|
+
maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.maxMonomerLength;
|
|
167
149
|
}
|
|
168
150
|
|
|
169
|
-
let
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
151
|
+
let seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
|
|
152
|
+
if (!seqColTemp) {
|
|
153
|
+
seqColTemp = new MonomerPlacer(view, tableCol,
|
|
154
|
+
() => {
|
|
155
|
+
const uh = UnitsHandler.getOrCreate(tableCol);
|
|
156
|
+
return {
|
|
157
|
+
unitsHandler: uh,
|
|
158
|
+
monomerCharWidth: 7, separatorWidth: !uh.isMsa() ? gapRenderer : 8,
|
|
159
|
+
monomerToShort: monomerToShortFunction, monomerLengthLimit: maxLengthOfMonomer,
|
|
160
|
+
monomerLib: getBioLib()
|
|
161
|
+
};
|
|
180
162
|
});
|
|
181
|
-
samples += 1;
|
|
182
|
-
}
|
|
183
|
-
const minLength = 3 * 7;
|
|
184
|
-
for (let i = 0; i <= maxIndex; i++) {
|
|
185
|
-
if (maxLengthWords[i] < minLength) maxLengthWords[i] = minLength;
|
|
186
|
-
const maxLengthWordSum: any = {};
|
|
187
|
-
maxLengthWordSum[0] = maxLengthWords[0];
|
|
188
|
-
for (let i = 1; i <= maxIndex; i++) maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
|
|
189
|
-
colTemp[tempTAGS.bioSumMaxLengthWords] = maxLengthWordSum;
|
|
190
|
-
colTemp[tempTAGS.bioMaxIndex] = maxIndex;
|
|
191
|
-
colTemp[tempTAGS.bioMaxLengthWords] = maxLengthWords;
|
|
192
|
-
gridCell.cell.column.setTag(mmcrTags.calculated, splitLimit.toString());
|
|
193
|
-
}
|
|
194
|
-
} else {
|
|
195
|
-
maxLengthWords = colTemp[tempTAGS.bioMaxLengthWords];
|
|
196
163
|
}
|
|
197
164
|
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let drawStyle = DrawStyle.classic;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (aligned && aligned.includes('MSA') && units == NOTATION.SEPARATOR)
|
|
205
|
-
drawStyle = DrawStyle.MSA;
|
|
165
|
+
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
166
|
+
seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!);
|
|
167
|
+
const maxIndex = maxLengthWords.length;
|
|
206
168
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
g.fillStyle = undefinedColor;
|
|
210
|
-
const last = index === subParts.length - 1;
|
|
211
|
-
x1 = printLeftOrCentered(x1, y, w, h,
|
|
212
|
-
g, amino, color, 0, true, 1.0, separator, last, drawStyle,
|
|
213
|
-
maxLengthWords, index, gridCell, referenceSequence, maxLengthOfMonomer);
|
|
214
|
-
return minDistanceRenderer <= w;
|
|
215
|
-
});
|
|
169
|
+
// Store updated seqColTemp to the col temp
|
|
170
|
+
if (seqColTemp.updated) tableColTemp[tempTAGS.bioSeqCol] = seqColTemp;
|
|
216
171
|
|
|
217
|
-
g.
|
|
218
|
-
|
|
172
|
+
g.save();
|
|
173
|
+
try {
|
|
174
|
+
const grid = gridCell.gridRow !== -1 ? gridCell.grid : null;
|
|
175
|
+
const value: any = gridCell.cell.value;
|
|
176
|
+
const paletteType = tableCol.getTag(bioTAGS.alphabet);
|
|
177
|
+
const minDistanceRenderer = 50;
|
|
178
|
+
w = getUpdatedWidth(grid, g, x, w);
|
|
179
|
+
g.beginPath();
|
|
180
|
+
g.rect(x + this.padding, y + this.padding, w - this.padding - 1, h - this.padding * 2);
|
|
181
|
+
g.clip();
|
|
182
|
+
g.font = '12px monospace';
|
|
183
|
+
g.textBaseline = 'top';
|
|
184
|
+
|
|
185
|
+
//TODO: can this be replaced/merged with splitSequence?
|
|
186
|
+
const units = tableCol.getTag(DG.TAGS.UNITS);
|
|
187
|
+
const aligned: string = tableCol.getTag(bioTAGS.aligned);
|
|
188
|
+
|
|
189
|
+
const palette = getPaletteByType(paletteType);
|
|
190
|
+
|
|
191
|
+
const separator = tableCol.getTag(bioTAGS.separator) ?? '';
|
|
192
|
+
const splitLimit = w / 5;
|
|
193
|
+
const splitterFunc: SplitterFunc = getSplitter(units, separator, splitLimit);
|
|
194
|
+
|
|
195
|
+
const tempReferenceSequence: string | null = tableColTemp[tempTAGS.referenceSequence];
|
|
196
|
+
const tempCurrentWord: string | null = tableColTemp[tempTAGS.currentWord];
|
|
197
|
+
const referenceSequence: string[] = splitterFunc(
|
|
198
|
+
((tempReferenceSequence != null) && (tempReferenceSequence != '')) ?
|
|
199
|
+
tempReferenceSequence : tempCurrentWord ?? '');
|
|
200
|
+
|
|
201
|
+
// let maxLengthWords: { [pos: number]: number } = {};
|
|
202
|
+
// if (tableCol.getTag(rndrTAGS.calculatedCellRender) !== splitLimit.toString()) {
|
|
203
|
+
// let sampleCount = 0;
|
|
204
|
+
// while (sampleCount < Math.min(tableCol.length, 100)) {
|
|
205
|
+
// const rowIdx: number = sampleCount;
|
|
206
|
+
// const column = tableCol.get(rowIdx);
|
|
207
|
+
// const subParts: string[] = splitterFunc(column);
|
|
208
|
+
// for (const [index, amino] of subParts.entries()) {
|
|
209
|
+
// const textSize = monomerToShortFunction(amino, maxLengthOfMonomer).length * 7 + gapRenderer;
|
|
210
|
+
// if (textSize > (maxLengthWords[index] ?? 0))
|
|
211
|
+
// maxLengthWords[index] = textSize;
|
|
212
|
+
// if (index > maxIndex) maxIndex = index;
|
|
213
|
+
// }
|
|
214
|
+
// sampleCount += 1;
|
|
215
|
+
// }
|
|
216
|
+
// const minLength = 3 * 7;
|
|
217
|
+
// for (let i = 0; i <= maxIndex; i++) {
|
|
218
|
+
// if (maxLengthWords[i] < minLength) maxLengthWords[i] = minLength;
|
|
219
|
+
// const maxLengthWordSum: { [pos: number]: number } = {};
|
|
220
|
+
// maxLengthWordSum[0] = maxLengthWords[0];
|
|
221
|
+
// for (let i = 1; i <= maxIndex; i++) maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
|
|
222
|
+
// colTemp[tempTAGS.bioSumMaxLengthWords] = maxLengthWordSum;
|
|
223
|
+
// colTemp[tempTAGS.bioMaxIndex] = maxIndex;
|
|
224
|
+
// colTemp[tempTAGS.bioMaxLengthWords] = maxLengthWords;
|
|
225
|
+
// tableCol.setTag(rndrTAGS.calculatedCellRender, splitLimit.toString());
|
|
226
|
+
// }
|
|
227
|
+
// } else {
|
|
228
|
+
// maxLengthWords = colTemp[tempTAGS.bioMaxLengthWords];
|
|
229
|
+
// }
|
|
230
|
+
|
|
231
|
+
const subParts: string[] = splitterFunc(value);
|
|
232
|
+
/* let x1 = x; */
|
|
233
|
+
let color = undefinedColor;
|
|
234
|
+
let drawStyle = DrawStyle.classic;
|
|
235
|
+
|
|
236
|
+
if (aligned && aligned.includes('MSA') && units == NOTATION.SEPARATOR)
|
|
237
|
+
drawStyle = DrawStyle.MSA;
|
|
238
|
+
|
|
239
|
+
for (const [index, amino] of subParts.entries()) {
|
|
240
|
+
color = palette.get(amino);
|
|
241
|
+
g.fillStyle = undefinedColor;
|
|
242
|
+
const last = index === subParts.length - 1;
|
|
243
|
+
/*x1 = */
|
|
244
|
+
printLeftOrCentered(x + this.padding, y, w, h,
|
|
245
|
+
g, amino, color, 0, true, 1.0, separator, last, drawStyle,
|
|
246
|
+
maxLengthWordsSum, index, gridCell, referenceSequence, maxLengthOfMonomer);
|
|
247
|
+
if (minDistanceRenderer > w) break;
|
|
248
|
+
}
|
|
249
|
+
} catch (err: any) {
|
|
250
|
+
const errMsg: string = err instanceof Error ? err.message : !!err ? err.toString() : 'Error \'undefined\'';
|
|
251
|
+
_package.logger.error(`Bio: MacromoleculeSequenceCellRenderer.render() error: ${errMsg}`);
|
|
252
|
+
//throw err; // Do not throw to prevent disabling renderer
|
|
253
|
+
} finally {
|
|
254
|
+
g.restore();
|
|
255
|
+
}
|
|
219
256
|
}
|
|
220
257
|
}
|
|
221
258
|
|
package/src/utils/convert.ts
CHANGED
|
@@ -4,8 +4,10 @@ import * as grok from 'datagrok-api/grok';
|
|
|
4
4
|
|
|
5
5
|
import $ from 'cash-dom';
|
|
6
6
|
import {Subscription} from 'rxjs';
|
|
7
|
-
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
+
import {NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
8
|
import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
9
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
10
|
+
import {expect} from '@datagrok-libraries/utils/src/test';
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
let convertDialog: DG.Dialog | null = null;
|
|
@@ -127,6 +129,8 @@ export async function convertDo(
|
|
|
127
129
|
newColumn.semType = semType;
|
|
128
130
|
|
|
129
131
|
// call to calculate 'cell.renderer' tag
|
|
132
|
+
const newUH = UnitsHandler.getOrCreate(newColumn);
|
|
133
|
+
expect(newUH.isMsa(), true);
|
|
130
134
|
await grok.data.detectSemanticTypes(srcCol.dataFrame);
|
|
131
135
|
|
|
132
136
|
return newColumn;
|