@datagrok/bio 2.1.10 → 2.1.12
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 +1 -0
- package/detectors.js +5 -4
- package/dist/package-test.js +2182 -57664
- package/dist/package.js +1773 -57252
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +301 -250
- package/package.json +10 -12
- package/src/analysis/sequence-activity-cliffs.ts +5 -5
- package/src/analysis/sequence-diversity-viewer.ts +3 -2
- package/src/analysis/sequence-search-base-viewer.ts +2 -1
- package/src/analysis/sequence-similarity-viewer.ts +2 -2
- package/src/calculations/monomerLevelMols.ts +3 -3
- package/src/package.ts +28 -25
- package/src/substructure-search/substructure-search.ts +9 -9
- package/src/tests/Palettes-test.ts +9 -9
- package/src/tests/WebLogo-positions-test.ts +64 -57
- package/src/tests/bio-tests.ts +31 -21
- package/src/tests/checkInputColumn-tests.ts +17 -17
- package/src/tests/converters-test.ts +30 -30
- package/src/tests/detectors-benchmark-tests.ts +15 -16
- package/src/tests/detectors-tests.ts +31 -24
- package/src/tests/fasta-export-tests.ts +2 -3
- package/src/tests/renderers-test.ts +17 -15
- package/src/tests/splitters-test.ts +3 -3
- package/src/tests/utils/sequences-generators.ts +7 -7
- package/src/utils/cell-renderer.ts +33 -24
- package/src/utils/convert.ts +10 -10
- package/src/utils/multiple-sequence-alignment.ts +6 -7
- package/src/utils/save-as-fasta.ts +8 -8
- package/src/viewers/vd-regions-viewer.ts +15 -14
- package/tsconfig.json +1 -1
- package/jest.config.js +0 -33
- package/src/__jest__/remote.test.ts +0 -77
- package/src/__jest__/test-node.ts +0 -98
- package/test-Bio-62cc009524f3-e7a922ae.html +0 -392
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
4
3
|
|
|
5
4
|
import {after, before, category, delay, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
6
5
|
|
|
@@ -9,6 +8,7 @@ import {convertDo} from '../utils/convert';
|
|
|
9
8
|
import {SEM_TYPES, TAGS} from '../utils/constants';
|
|
10
9
|
import {generateLongSequence, generateManySequences, performanceTest} from './utils/sequences-generators';
|
|
11
10
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
11
|
+
import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS, UnitsHandler} from '@datagrok-libraries/bio';
|
|
12
12
|
|
|
13
13
|
category('renderers', () => {
|
|
14
14
|
let tvList: DG.TableView[];
|
|
@@ -103,7 +103,7 @@ category('renderers', () => {
|
|
|
103
103
|
async function _rendererMacromoleculeDifference() {
|
|
104
104
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
105
105
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
106
|
-
seqDiffCol.tags[DG.TAGS.UNITS] =
|
|
106
|
+
seqDiffCol.tags[DG.TAGS.UNITS] = NOTATION.SEPARATOR;
|
|
107
107
|
seqDiffCol.tags[TAGS.SEPARATOR] = '/';
|
|
108
108
|
seqDiffCol.semType = SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
109
109
|
const df = DG.DataFrame.fromColumns([seqDiffCol]);
|
|
@@ -138,22 +138,22 @@ category('renderers', () => {
|
|
|
138
138
|
`semType="${srcSeqCol!.semType}", units="${srcSeqCol!.getTag(DG.TAGS.UNITS)}", ` +
|
|
139
139
|
`cell.renderer="${srcSeqCol!.getTag(DG.TAGS.CELL_RENDERER)}"`);
|
|
140
140
|
expect(srcSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
141
|
-
expect(srcSeqCol.getTag(DG.TAGS.UNITS),
|
|
142
|
-
expect(srcSeqCol.getTag(
|
|
143
|
-
expect(srcSeqCol.getTag(
|
|
141
|
+
expect(srcSeqCol.getTag(DG.TAGS.UNITS), NOTATION.FASTA);
|
|
142
|
+
expect(srcSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ);
|
|
143
|
+
expect(srcSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
|
|
144
144
|
expect(srcSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
|
|
145
145
|
|
|
146
146
|
const msaSeqCol: DG.Column = (await multipleSequenceAlignmentAny(df, srcSeqCol!))!;
|
|
147
147
|
tv.grid.invalidate();
|
|
148
148
|
|
|
149
149
|
expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
|
|
150
|
-
expect(msaSeqCol.getTag(DG.TAGS.UNITS),
|
|
151
|
-
expect(msaSeqCol.getTag(
|
|
152
|
-
expect(msaSeqCol.getTag(
|
|
150
|
+
expect(msaSeqCol.getTag(DG.TAGS.UNITS), NOTATION.FASTA);
|
|
151
|
+
expect(msaSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ_MSA);
|
|
152
|
+
expect(msaSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
|
|
153
153
|
expect(msaSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
|
|
154
154
|
|
|
155
155
|
// check newColumn with UnitsHandler constructor
|
|
156
|
-
const uh:
|
|
156
|
+
const uh: UnitsHandler = new UnitsHandler(msaSeqCol);
|
|
157
157
|
|
|
158
158
|
dfList.push(df);
|
|
159
159
|
tvList.push(tv);
|
|
@@ -175,13 +175,13 @@ category('renderers', () => {
|
|
|
175
175
|
tvList.push(tv);
|
|
176
176
|
dfList.push(df);
|
|
177
177
|
|
|
178
|
-
const tgtCol: DG.Column = await convertDo(srcCol,
|
|
178
|
+
const tgtCol: DG.Column = await convertDo(srcCol, NOTATION.SEPARATOR, '/');
|
|
179
179
|
|
|
180
180
|
const resCellRenderer = tgtCol.getTag(DG.TAGS.CELL_RENDERER);
|
|
181
181
|
expect(resCellRenderer, 'sequence');
|
|
182
182
|
|
|
183
183
|
// check tgtCol with UnitsHandler constructor
|
|
184
|
-
const uh:
|
|
184
|
+
const uh: UnitsHandler = new UnitsHandler(tgtCol);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
async function _selectRendererBySemType() {
|
|
@@ -190,7 +190,7 @@ category('renderers', () => {
|
|
|
190
190
|
/**/
|
|
191
191
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
192
192
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
193
|
-
seqDiffCol.tags[DG.TAGS.UNITS] =
|
|
193
|
+
seqDiffCol.tags[DG.TAGS.UNITS] = NOTATION.SEPARATOR;
|
|
194
194
|
seqDiffCol.tags[TAGS.SEPARATOR] = '/';
|
|
195
195
|
seqDiffCol.semType = SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
196
196
|
const df = DG.DataFrame.fromColumns([seqDiffCol]);
|
|
@@ -200,10 +200,11 @@ category('renderers', () => {
|
|
|
200
200
|
|
|
201
201
|
await delay(100);
|
|
202
202
|
const renderer = seqDiffCol.getTag(DG.TAGS.CELL_RENDERER);
|
|
203
|
-
if (renderer !== 'MacromoleculeDifference') // this is value of MacromoleculeDifferenceCR.cellType
|
|
203
|
+
if (renderer !== 'MacromoleculeDifference') { // this is value of MacromoleculeDifferenceCR.cellType
|
|
204
204
|
throw new Error(`Units 'separator', separator '/' and semType 'MacromoleculeDifference' ` +
|
|
205
205
|
`have been manually set on column but after df was added as table, ` +
|
|
206
206
|
`view renderer has set to '${renderer}' instead of correct 'MacromoleculeDifference'.`);
|
|
207
|
+
}
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
/** GROK-11212 Do not overwrite / recalculate 'cell.renderer' tag that has been set programmatically
|
|
@@ -211,7 +212,7 @@ category('renderers', () => {
|
|
|
211
212
|
async function _setRendererManually() {
|
|
212
213
|
const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
|
|
213
214
|
['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
|
|
214
|
-
seqDiffCol.tags[DG.TAGS.UNITS] =
|
|
215
|
+
seqDiffCol.tags[DG.TAGS.UNITS] = NOTATION.SEPARATOR;
|
|
215
216
|
seqDiffCol.tags[TAGS.SEPARATOR] = '/';
|
|
216
217
|
seqDiffCol.semType = SEM_TYPES.MACROMOLECULE;
|
|
217
218
|
const tgtCellRenderer = 'MacromoleculeDifference';
|
|
@@ -224,9 +225,10 @@ category('renderers', () => {
|
|
|
224
225
|
|
|
225
226
|
await delay(100);
|
|
226
227
|
const resCellRenderer = seqDiffCol.getTag(DG.TAGS.CELL_RENDERER);
|
|
227
|
-
if (resCellRenderer !== tgtCellRenderer) // this is value of MacromoleculeDifferenceCR.cellType
|
|
228
|
+
if (resCellRenderer !== tgtCellRenderer) { // this is value of MacromoleculeDifferenceCR.cellType
|
|
228
229
|
throw new Error(`Tag 'cell.renderer' has been manually set to '${tgtCellRenderer}' for column ` +
|
|
229
230
|
`but after df was added as table, tag 'cell.renderer' has reset to '${resCellRenderer}' ` +
|
|
230
231
|
`instead of manual '${tgtCellRenderer}'.`);
|
|
232
|
+
}
|
|
231
233
|
}
|
|
232
234
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
5
4
|
|
|
6
5
|
import {after, before, category, test, expect, expectArray, expectObject} from '@datagrok-libraries/utils/src/test';
|
|
7
6
|
import * as C from '../utils/constants';
|
|
8
7
|
import {splitToMonomers, _package, getHelmMonomers} from '../package';
|
|
9
8
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
9
|
+
import {splitterAsFasta, splitterAsHelm} from '@datagrok-libraries/bio';
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
category('splitters', () => {
|
|
@@ -122,13 +122,13 @@ PEPTIDE1{hHis.Aca.Cys_SEt}$$$,5.72388
|
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
export async function _testFastaSplitter(src: string, tgt: string[]) {
|
|
125
|
-
const res: string[] =
|
|
125
|
+
const res: string[] = splitterAsFasta(src);
|
|
126
126
|
console.debug(`Bio: tests: splitters: src=${JSON.stringify(src)}, res=${JSON.stringify(res)} .`);
|
|
127
127
|
expectArray(res, tgt);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
export async function _testHelmSplitter(src: string, tgt: string[]) {
|
|
131
|
-
const res: string[] =
|
|
131
|
+
const res: string[] = splitterAsHelm(src);
|
|
132
132
|
console.debug(`Bio: tests: splitters: src=${JSON.stringify(src)}, res=${JSON.stringify(res)} .`);
|
|
133
133
|
expectArray(res, tgt);
|
|
134
134
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
-
import
|
|
4
|
+
import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
export function generateManySequences(): DG.Column[] {
|
|
8
|
-
|
|
8
|
+
const columns: DG.Column[] = [];
|
|
9
9
|
columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 6).fill('meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me')));
|
|
10
10
|
columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 6).fill('5.30751')));
|
|
11
11
|
return columns;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function generateLongSequence(): DG.Column[] {
|
|
15
|
-
|
|
15
|
+
const columns: DG.Column[] = [];
|
|
16
16
|
const longSequence = `meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`.repeat(10 ** 5);
|
|
17
17
|
columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 2).fill(longSequence)));
|
|
18
18
|
columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 2).fill('7.30751')));
|
|
@@ -21,10 +21,10 @@ export function generateLongSequence(): DG.Column[] {
|
|
|
21
21
|
|
|
22
22
|
export function setTagsMacromolecule(col: DG.Column) {
|
|
23
23
|
col.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
24
|
-
col.setTag(DG.TAGS.UNITS,
|
|
25
|
-
col.setTag(
|
|
26
|
-
col.setTag(
|
|
27
|
-
col.setTag(
|
|
24
|
+
col.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
25
|
+
col.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
26
|
+
col.setTag(bioTAGS.alphabet, ALPHABET.UN);
|
|
27
|
+
col.setTag(bioTAGS.separator, '/');
|
|
28
28
|
return col;
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -3,11 +3,20 @@ import * as DG from 'datagrok-api/dg';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
|
|
5
5
|
import {printLeftOrCentered, DrawStyle} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
6
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
7
6
|
import * as C from './constants';
|
|
7
|
+
import {
|
|
8
|
+
ALIGNMENT,
|
|
9
|
+
getPaletteByType,
|
|
10
|
+
getSplitter,
|
|
11
|
+
monomerToShort,
|
|
12
|
+
SeqPalette,
|
|
13
|
+
SplitterFunc,
|
|
14
|
+
TAGS as bioTAGS,
|
|
15
|
+
UnknownSeqPalettes
|
|
16
|
+
} from '@datagrok-libraries/bio';
|
|
8
17
|
|
|
9
18
|
const undefinedColor = 'rgb(100,100,100)';
|
|
10
|
-
const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string =
|
|
19
|
+
const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string = monomerToShort;
|
|
11
20
|
|
|
12
21
|
function getUpdatedWidth(grid: DG.Grid | null, g: CanvasRenderingContext2D, x: number, w: number): number {
|
|
13
22
|
return grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
@@ -46,7 +55,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
49
|
-
if (gridCell.cell.column.getTag(
|
|
58
|
+
if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
|
|
50
59
|
return;
|
|
51
60
|
|
|
52
61
|
const maxLengthWordsSum = gridCell.cell.column.temp['bio-sum-maxLengthWords'];
|
|
@@ -74,7 +83,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
74
83
|
}
|
|
75
84
|
left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
|
|
76
85
|
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
77
|
-
const splitterFunc:
|
|
86
|
+
const splitterFunc: SplitterFunc = getSplitter('separator', separator);
|
|
78
87
|
const subParts: string[] = splitterFunc(gridCell.cell.value);
|
|
79
88
|
(((subParts[left]?.length ?? 0) > 0)) ?
|
|
80
89
|
ui.tooltip.show(ui.div(subParts[left]), e.x + 16, e.y + 16) : ui.tooltip.hide();
|
|
@@ -95,7 +104,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
95
104
|
render(
|
|
96
105
|
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
|
|
97
106
|
cellStyle: DG.GridCellStyle
|
|
98
|
-
)
|
|
107
|
+
) {
|
|
99
108
|
const grid = gridCell.gridRow !== -1 ? gridCell.grid : null;
|
|
100
109
|
const cell = gridCell.cell;
|
|
101
110
|
const paletteType = gridCell.cell.column.getTag(C.TAGS.ALPHABET);
|
|
@@ -111,11 +120,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
111
120
|
//TODO: can this be replaced/merged with splitSequence?
|
|
112
121
|
const units = gridCell.cell.column.getTag(DG.TAGS.UNITS);
|
|
113
122
|
|
|
114
|
-
const palette =
|
|
123
|
+
const palette = getPaletteByType(paletteType);
|
|
115
124
|
|
|
116
125
|
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
117
126
|
const splitLimit = gridCell.bounds.width / 5;
|
|
118
|
-
const splitterFunc:
|
|
127
|
+
const splitterFunc: SplitterFunc = getSplitter(units, separator, splitLimit);
|
|
119
128
|
const referenceSequence: string[] = splitterFunc(((gridCell.cell.column?.temp['reference-sequence'] != null) && (gridCell.cell.column?.temp['reference-sequence'] != ''))
|
|
120
129
|
? gridCell.cell.column.temp['reference-sequence'] : gridCell.cell.column.temp['current-word'] ?? '');
|
|
121
130
|
const monomerWidth = (gridCell.cell.column?.temp['monomer-width'] != null) ? gridCell.cell.column.temp['monomer-width'] : 'short';
|
|
@@ -146,7 +155,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
146
155
|
});
|
|
147
156
|
samples += 1;
|
|
148
157
|
}
|
|
149
|
-
|
|
158
|
+
const minLength = 3 * 7;
|
|
150
159
|
for (let i = 0; i <= maxIndex; i++) {
|
|
151
160
|
if (maxLengthWords[i] < minLength) {
|
|
152
161
|
maxLengthWords[i] = minLength;
|
|
@@ -168,15 +177,15 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
168
177
|
const subParts: string[] = splitterFunc(cell.value);
|
|
169
178
|
let x1 = x;
|
|
170
179
|
let color = undefinedColor;
|
|
171
|
-
let drawStyle =
|
|
180
|
+
let drawStyle = DrawStyle.classic;
|
|
172
181
|
if (gridCell.cell.column.getTag('aligned').includes('MSA') && gridCell.cell.column.getTag('units') === 'separator')
|
|
173
|
-
drawStyle =
|
|
182
|
+
drawStyle = DrawStyle.MSA;
|
|
174
183
|
|
|
175
184
|
subParts.every((amino, index) => {
|
|
176
185
|
color = palette.get(amino);
|
|
177
186
|
g.fillStyle = undefinedColor;
|
|
178
|
-
|
|
179
|
-
x1 =
|
|
187
|
+
const last = index === subParts.length - 1;
|
|
188
|
+
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell, referenceSequence, maxLengthOfMonomer);
|
|
180
189
|
return x1 - minDistanceRenderer - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x) <= gridCell.bounds.width;
|
|
181
190
|
});
|
|
182
191
|
|
|
@@ -212,14 +221,14 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
|
|
|
212
221
|
g.textBaseline = 'middle';
|
|
213
222
|
g.textAlign = 'center';
|
|
214
223
|
|
|
215
|
-
const palette =
|
|
224
|
+
const palette = getPaletteByType(gridCell.cell.column.getTag(C.TAGS.ALPHABET));
|
|
216
225
|
const s: string = gridCell.cell.value;
|
|
217
226
|
if (!s)
|
|
218
227
|
return;
|
|
219
228
|
const color = palette.get(s);
|
|
220
229
|
|
|
221
230
|
g.fillStyle = color;
|
|
222
|
-
g.fillText(s, x + (w / 2), y + (h / 2), w);
|
|
231
|
+
g.fillText(monomerToShort(s, 3), x + (w / 2), y + (h / 2), w);
|
|
223
232
|
}
|
|
224
233
|
}
|
|
225
234
|
|
|
@@ -255,7 +264,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
|
255
264
|
w = getUpdatedWidth(grid, g, x, w);
|
|
256
265
|
//TODO: can this be replaced/merged with splitSequence?
|
|
257
266
|
const [s1, s2] = s.split('#');
|
|
258
|
-
const splitter =
|
|
267
|
+
const splitter = getSplitter(units, separator);
|
|
259
268
|
const subParts1 = splitter(s1);
|
|
260
269
|
const subParts2 = splitter(s2);
|
|
261
270
|
drawMoleculeDifferenceOnCanvas(g, x, y, w, h, subParts1, subParts2, units);
|
|
@@ -272,8 +281,8 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
272
281
|
subParts2: string [],
|
|
273
282
|
units: string,
|
|
274
283
|
fullStringLength?: boolean,
|
|
275
|
-
molDifferences?: { [key: number]: HTMLCanvasElement }
|
|
276
|
-
|
|
284
|
+
molDifferences?: { [key: number]: HTMLCanvasElement }
|
|
285
|
+
): void {
|
|
277
286
|
if (subParts1.length !== subParts2.length) {
|
|
278
287
|
const emptyMonomersArray = new Array<string>(Math.abs(subParts1.length - subParts2.length)).fill('');
|
|
279
288
|
subParts1.length > subParts2.length ?
|
|
@@ -297,9 +306,9 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
297
306
|
g.font = '12px monospace';
|
|
298
307
|
g.textBaseline = 'top';
|
|
299
308
|
|
|
300
|
-
let palette:
|
|
309
|
+
let palette: SeqPalette = UnknownSeqPalettes.Color;
|
|
301
310
|
if (units != 'HELM')
|
|
302
|
-
palette =
|
|
311
|
+
palette = getPaletteByType(units.substring(units.length - 2));
|
|
303
312
|
|
|
304
313
|
const vShift = 7;
|
|
305
314
|
for (let i = 0; i < subParts1.length; i++) {
|
|
@@ -309,12 +318,12 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
309
318
|
|
|
310
319
|
if (amino1 != amino2) {
|
|
311
320
|
const color2 = palette.get(amino2);
|
|
312
|
-
const subX0 =
|
|
313
|
-
const subX1 =
|
|
321
|
+
const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
|
|
322
|
+
const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
|
|
314
323
|
updatedX = Math.max(subX1, subX0);
|
|
315
324
|
if (molDifferences)
|
|
316
325
|
molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
|
|
317
|
-
} else { updatedX =
|
|
326
|
+
} else { updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5); }
|
|
318
327
|
updatedX += 4;
|
|
319
328
|
}
|
|
320
329
|
g.restore();
|
|
@@ -338,7 +347,7 @@ function createDifferenceCanvas(
|
|
|
338
347
|
canvas.width = width + 4;
|
|
339
348
|
context.font = '12px monospace';
|
|
340
349
|
context.textBaseline = 'top';
|
|
341
|
-
|
|
342
|
-
|
|
350
|
+
printLeftOrCentered(0, y - shift, width, h, context, amino1, color1, 0, true);
|
|
351
|
+
printLeftOrCentered(0, y + shift, width, h, context, amino2, color2, 0, true);
|
|
343
352
|
return canvas;
|
|
344
353
|
}
|
package/src/utils/convert.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as grok from 'datagrok-api/grok';
|
|
4
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
5
4
|
|
|
6
5
|
import $ from 'cash-dom';
|
|
7
6
|
import {Subscription} from 'rxjs';
|
|
7
|
+
import {NOTATION, NotationConverter} from '@datagrok-libraries/bio';
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
let convertDialog: DG.Dialog | null = null;
|
|
@@ -16,13 +16,13 @@ let convertDialogSubs: Subscription[] = [];
|
|
|
16
16
|
* @param {DG.column} col Column with 'Macromolecule' semantic type
|
|
17
17
|
*/
|
|
18
18
|
export function convert(col: DG.Column): void {
|
|
19
|
-
const converter = new
|
|
20
|
-
const currentNotation:
|
|
19
|
+
const converter = new NotationConverter(col);
|
|
20
|
+
const currentNotation: NOTATION = converter.notation;
|
|
21
21
|
//TODO: read all notations
|
|
22
22
|
const notations = [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
NOTATION.FASTA,
|
|
24
|
+
NOTATION.SEPARATOR,
|
|
25
|
+
NOTATION.HELM
|
|
26
26
|
];
|
|
27
27
|
const separatorArray = ['-', '.', '/'];
|
|
28
28
|
const filteredNotations = notations.filter((e) => e !== currentNotation);
|
|
@@ -32,7 +32,7 @@ export function convert(col: DG.Column): void {
|
|
|
32
32
|
|
|
33
33
|
// hide the separator input for non-SEPARATOR target notations
|
|
34
34
|
const toggleSeparator = () => {
|
|
35
|
-
if (targetNotationInput.value !==
|
|
35
|
+
if (targetNotationInput.value !== NOTATION.SEPARATOR)
|
|
36
36
|
$(separatorInput.root).hide();
|
|
37
37
|
else
|
|
38
38
|
$(separatorInput.root).show();
|
|
@@ -63,7 +63,7 @@ export function convert(col: DG.Column): void {
|
|
|
63
63
|
separatorInput.root
|
|
64
64
|
]))
|
|
65
65
|
.onOK(async () => {
|
|
66
|
-
const targetNotation = targetNotationInput.value as
|
|
66
|
+
const targetNotation = targetNotationInput.value as NOTATION;
|
|
67
67
|
const separator: string | null = separatorInput.value;
|
|
68
68
|
|
|
69
69
|
await convertDo(col, targetNotation, separator);
|
|
@@ -80,9 +80,9 @@ export function convert(col: DG.Column): void {
|
|
|
80
80
|
|
|
81
81
|
/** Creates a new column with converted sequences and detects its semantic type */
|
|
82
82
|
export async function convertDo(
|
|
83
|
-
srcCol: DG.Column, targetNotation:
|
|
83
|
+
srcCol: DG.Column, targetNotation: NOTATION, separator: string | null
|
|
84
84
|
): Promise<DG.Column> {
|
|
85
|
-
const converter = new
|
|
85
|
+
const converter = new NotationConverter(srcCol);
|
|
86
86
|
const newColumn = converter.convert(targetNotation, separator);
|
|
87
87
|
srcCol.dataFrame.columns.add(newColumn);
|
|
88
88
|
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
6
5
|
|
|
7
6
|
import {FastaFileHandler} from '@datagrok-libraries/bio/src/utils/fasta-handler';
|
|
8
|
-
|
|
7
|
+
import {TAGS as bioTAGS} from '@datagrok-libraries/bio';
|
|
9
8
|
//@ts-ignore
|
|
10
9
|
import Aioli from '@biowasm/aioli';
|
|
11
10
|
|
|
@@ -39,7 +38,7 @@ export async function runKalign(srcCol: DG.Column, isAligned = false, unUsedName
|
|
|
39
38
|
const fasta = _stringsToFasta(sequences);
|
|
40
39
|
const CLI = await new Aioli([
|
|
41
40
|
'base/1.0.0',
|
|
42
|
-
{tool: 'kalign', version: '3.3.1', reinit: true
|
|
41
|
+
{tool: 'kalign', version: '3.3.1', reinit: true}
|
|
43
42
|
]);
|
|
44
43
|
|
|
45
44
|
console.log(['fasta.length =', fasta.length]);
|
|
@@ -59,14 +58,14 @@ export async function runKalign(srcCol: DG.Column, isAligned = false, unUsedName
|
|
|
59
58
|
// units
|
|
60
59
|
const srcUnits = srcCol.getTag(DG.TAGS.UNITS);
|
|
61
60
|
//aligned
|
|
62
|
-
const srcAligned = srcCol.getTag(
|
|
61
|
+
const srcAligned = srcCol.getTag(bioTAGS.aligned);
|
|
63
62
|
const tgtAligned = srcAligned + '.MSA';
|
|
64
63
|
//alphabet
|
|
65
|
-
const srcAlphabet = srcCol.getTag(
|
|
64
|
+
const srcAlphabet = srcCol.getTag(bioTAGS.alphabet);
|
|
66
65
|
|
|
67
66
|
tgtCol.setTag(DG.TAGS.UNITS, srcUnits);
|
|
68
|
-
tgtCol.setTag(
|
|
69
|
-
tgtCol.setTag(
|
|
67
|
+
tgtCol.setTag(bioTAGS.aligned, tgtAligned);
|
|
68
|
+
tgtCol.setTag(bioTAGS.alphabet, srcAlphabet);
|
|
70
69
|
tgtCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
71
70
|
return tgtCol;
|
|
72
71
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as grok from 'datagrok-api/grok';
|
|
4
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
5
4
|
|
|
6
5
|
import wu from 'wu';
|
|
6
|
+
import {splitterAsFasta, SplitterFunc, UnitsHandler} from '@datagrok-libraries/bio';
|
|
7
7
|
|
|
8
8
|
const FASTA_LINE_WIDTH = 60;
|
|
9
9
|
|
|
10
10
|
/** Shows dialog to select id columns list and seq column, builds and downloads FASTA content */
|
|
11
11
|
export function saveAsFastaUI() {
|
|
12
12
|
// Use grid for column order adjusted by user
|
|
13
|
-
|
|
13
|
+
const grid: DG.Grid = grok.shell.tv.grid;
|
|
14
14
|
|
|
15
15
|
const idGColList: DG.GridColumn[] = wu.count(0).take(grid.columns.length)
|
|
16
16
|
.map((colI: number) => grid.columns.byIndex(colI)!)
|
|
@@ -27,7 +27,7 @@ export function saveAsFastaUI() {
|
|
|
27
27
|
.filter((gc: DG.GridColumn) => {
|
|
28
28
|
const col: DG.Column | null = gc.column;
|
|
29
29
|
if (col && col.semType === DG.SEMTYPE.MACROMOLECULE) {
|
|
30
|
-
const uh = new
|
|
30
|
+
const uh = new UnitsHandler(col);
|
|
31
31
|
return uh.isFasta();
|
|
32
32
|
}
|
|
33
33
|
return false;
|
|
@@ -39,7 +39,7 @@ export function saveAsFastaUI() {
|
|
|
39
39
|
|
|
40
40
|
const lineWidthInput = ui.intInput('FASTA line width', FASTA_LINE_WIDTH);
|
|
41
41
|
|
|
42
|
-
ui.dialog({title: 'Save as FASTA'
|
|
42
|
+
ui.dialog({title: 'Save as FASTA'})
|
|
43
43
|
.add(ui.inputs([
|
|
44
44
|
idGColListInput,
|
|
45
45
|
seqColInput,
|
|
@@ -57,7 +57,7 @@ export function saveAsFastaUI() {
|
|
|
57
57
|
|
|
58
58
|
const resFastaTxt: string = saveAsFastaDo(valueIdColList, valueSeqCol!, valueLineWidth);
|
|
59
59
|
|
|
60
|
-
const aEl: HTMLAnchorElement = document.createElement('a'
|
|
60
|
+
const aEl: HTMLAnchorElement = document.createElement('a');
|
|
61
61
|
aEl.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(resFastaTxt)}`);
|
|
62
62
|
aEl.setAttribute('download', `${grid.dataFrame.name}.fasta`);
|
|
63
63
|
aEl.click();
|
|
@@ -69,7 +69,7 @@ export function saveAsFastaUI() {
|
|
|
69
69
|
export function saveAsFastaDo(
|
|
70
70
|
idColList: DG.Column[], seqCol: DG.Column, lineWidth: number = FASTA_LINE_WIDTH, lineSeparator: string = '\n'
|
|
71
71
|
): string {
|
|
72
|
-
const splitter:
|
|
72
|
+
const splitter: SplitterFunc = splitterAsFasta;
|
|
73
73
|
|
|
74
74
|
const fastaLines: string[] = [];
|
|
75
75
|
|
|
@@ -91,7 +91,7 @@ export function saveAsFastaDo(
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/* split sequence for monomers to prevent wrapping monomer partially */
|
|
94
|
-
export function wrapSequence(seq: string, splitter:
|
|
94
|
+
export function wrapSequence(seq: string, splitter: SplitterFunc, lineWidth: number = FASTA_LINE_WIDTH): string[] {
|
|
95
95
|
const seqMonomerList = splitter(seq);
|
|
96
96
|
let seqPos: number = 0;
|
|
97
97
|
const seqLength: number = seqMonomerList.length;
|
|
@@ -106,4 +106,4 @@ export function wrapSequence(seq: string, splitter: bio.SplitterFunc, lineWidth:
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
return seqLineList;
|
|
109
|
-
}
|
|
109
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
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
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import {IVdRegionsViewer, PositionHeight, VdRegion, VdRegionType, WebLogoViewer} from '@datagrok-libraries/bio';
|
|
6
|
+
|
|
7
|
+
const vrt = VdRegionType;
|
|
7
8
|
|
|
8
9
|
// Positions of regions for numbering schemes
|
|
9
10
|
// http://www.bioinf.org.uk/abs/info.html
|
|
@@ -34,7 +35,7 @@ const vrt = bio.VdRegionType;
|
|
|
34
35
|
/** Viewer with tabs based on description of chain regions.
|
|
35
36
|
* Used to define regions of an immunoglobulin LC.
|
|
36
37
|
*/
|
|
37
|
-
export class VdRegionsViewer extends DG.JsViewer implements
|
|
38
|
+
export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
38
39
|
// private regionsDf: DG.DataFrame;
|
|
39
40
|
private regionsFg: DG.FilterGroup | null = null;
|
|
40
41
|
// private regionsTV: DG.TableView;
|
|
@@ -43,7 +44,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
43
44
|
private isOpened: boolean = false;
|
|
44
45
|
private panelNode: DG.DockNode | null = null;
|
|
45
46
|
|
|
46
|
-
public regions:
|
|
47
|
+
public regions: VdRegion[] = [];
|
|
47
48
|
public regionTypes: string[];
|
|
48
49
|
public chains: string[];
|
|
49
50
|
public sequenceColumnNamePostfix: string;
|
|
@@ -58,7 +59,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// TODO: .onTableAttached is not calling on dataFrame set, onPropertyChanged also not calling
|
|
61
|
-
public async setDf(value: DG.DataFrame, regions:
|
|
62
|
+
public async setDf(value: DG.DataFrame, regions: VdRegion[]) {
|
|
62
63
|
console.debug('VdRegionsViewer.setDf()');
|
|
63
64
|
await this.destroyView();
|
|
64
65
|
this.regions = regions;
|
|
@@ -78,8 +79,8 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
78
79
|
|
|
79
80
|
this.skipEmptyPositions = this.bool('skipEmptyPositions', false);
|
|
80
81
|
this.positionWidth = this.float('positionWidth', 16);
|
|
81
|
-
this.positionHeight = this.string('positionHeight',
|
|
82
|
-
{choices: Object.keys(
|
|
82
|
+
this.positionHeight = this.string('positionHeight', PositionHeight.Entropy,
|
|
83
|
+
{choices: Object.keys(PositionHeight)});
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
public async init() {
|
|
@@ -180,7 +181,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
180
181
|
//#region -- View --
|
|
181
182
|
private host: HTMLElement | null = null;
|
|
182
183
|
private mainLayout: HTMLTableElement | null = null;
|
|
183
|
-
private logos: { [chain: string]:
|
|
184
|
+
private logos: { [chain: string]: WebLogoViewer }[] = [];
|
|
184
185
|
|
|
185
186
|
private async destroyView(): Promise<void> {
|
|
186
187
|
// TODO: Unsubscribe from and remove all view elements
|
|
@@ -200,16 +201,16 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
200
201
|
const colNames: { [chain: string]: string } = Object.assign({},
|
|
201
202
|
...this.chains.map((chain) => ({[chain]: `${chain} ${this.sequenceColumnNamePostfix}`})));
|
|
202
203
|
|
|
203
|
-
const regionsFiltered:
|
|
204
|
+
const regionsFiltered: VdRegion[] = this.regions.filter((r: VdRegion) => this.regionTypes.includes(r.type));
|
|
204
205
|
|
|
205
206
|
const orderList: number[] = Array.from(new Set(regionsFiltered.map((r) => r.order))).sort();
|
|
206
207
|
|
|
207
208
|
this.logos = [];
|
|
208
209
|
|
|
209
210
|
for (let orderI = 0; orderI < orderList.length; orderI++) {
|
|
210
|
-
const regionChains: { [chain: string]:
|
|
211
|
+
const regionChains: { [chain: string]: WebLogoViewer } = {};
|
|
211
212
|
for (const chain of this.chains) {
|
|
212
|
-
const region:
|
|
213
|
+
const region: VdRegion | undefined = regionsFiltered
|
|
213
214
|
.find((r) => r.order == orderList[orderI] && r.chain == chain);
|
|
214
215
|
regionChains[chain] = (await this.dataFrame.plot.fromType('WebLogo', {
|
|
215
216
|
sequenceColumnName: colNames[chain],
|
|
@@ -219,7 +220,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
219
220
|
skipEmptyPositions: this.skipEmptyPositions,
|
|
220
221
|
positionWidth: this.positionWidth,
|
|
221
222
|
positionHeight: this.positionHeight,
|
|
222
|
-
})) as unknown as
|
|
223
|
+
})) as unknown as WebLogoViewer;
|
|
223
224
|
}
|
|
224
225
|
// WebLogo creation fires onRootSizeChanged event even before control being added to this.logos
|
|
225
226
|
this.logos[orderI] = regionChains;
|
|
@@ -244,7 +245,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
244
245
|
})] : []),
|
|
245
246
|
// List with controls for regions
|
|
246
247
|
...[...Array(orderList.length).keys()].map((orderI) => {
|
|
247
|
-
const wl:
|
|
248
|
+
const wl: WebLogoViewer = this.logos[orderI][chain];
|
|
248
249
|
wl.root.style.height = '100%';
|
|
249
250
|
|
|
250
251
|
const resDiv = ui.div([wl.root]/*`${chain} ${regionsFiltered[rI]}`*/, {
|
|
@@ -261,7 +262,7 @@ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer
|
|
|
261
262
|
},
|
|
262
263
|
['', ...[...Array(orderList.length).keys()].map(
|
|
263
264
|
(orderI: number) => regionsFiltered.find(
|
|
264
|
-
(r:
|
|
265
|
+
(r: VdRegion) => r.order == orderList[orderI] && r.chain == this.chains[0]
|
|
265
266
|
)!.name || 'Name')]
|
|
266
267
|
);
|
|
267
268
|
this.mainLayout.className = 'mlb-vd-regions-viewer-table2';
|
package/tsconfig.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// "incremental": true, /* Enable incremental compilation */
|
|
7
7
|
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
|
8
8
|
"module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
|
9
|
-
"lib": ["es2020", "dom", "ES2021.String"],
|
|
9
|
+
"lib": ["es2020", "dom", "ES2021.String"], /* Specify library files to be included in the compilation. */
|
|
10
10
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
11
11
|
// "checkJs": true, /* Report errors in .js files. */
|
|
12
12
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
package/jest.config.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
'roots': [
|
|
3
|
-
'<rootDir>/src',
|
|
4
|
-
],
|
|
5
|
-
'testMatch': [
|
|
6
|
-
'**/__jest__/**/*.test.+(ts|tsx)',
|
|
7
|
-
],
|
|
8
|
-
moduleFileExtensions: [
|
|
9
|
-
'ts',
|
|
10
|
-
'js',
|
|
11
|
-
],
|
|
12
|
-
'transform': {
|
|
13
|
-
'^.+\\.(ts|tsx)$': 'ts-jest',
|
|
14
|
-
},
|
|
15
|
-
transformIgnorePatterns: ['^.+\\.js$'],
|
|
16
|
-
globals: {
|
|
17
|
-
'ts-jest': {
|
|
18
|
-
'tsconfig': {
|
|
19
|
-
'target': 'es6',
|
|
20
|
-
'module': 'es2020',
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
reporters: [
|
|
25
|
-
'default',
|
|
26
|
-
[
|
|
27
|
-
'./node_modules/jest-html-reporter',
|
|
28
|
-
{
|
|
29
|
-
'includeConsoleLog': true,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
],
|
|
33
|
-
};
|