@datagrok/bio 2.15.2 → 2.15.5
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/CHANGELOG.md +32 -0
- package/detectors.js +3 -1
- package/dist/284.js +1 -1
- package/dist/284.js.map +1 -1
- package/dist/455.js +2 -0
- package/dist/455.js.map +1 -0
- package/dist/980.js +1 -1
- package/dist/980.js.map +1 -1
- package/dist/package-test.js +3 -3
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/files/tests/to-atomic-level-msa-fasta-output.csv +683 -683
- package/files/tests/to-atomic-level-msa-separator-output.csv +104 -104
- package/package.json +9 -9
- package/src/analysis/sequence-activity-cliffs.ts +3 -1
- package/src/calculations/monomerLevelMols.ts +2 -1
- package/src/demo/bio03-atomic-level.ts +1 -1
- package/src/package-test.ts +6 -1
- package/src/package.ts +151 -38
- package/src/tests/WebLogo-positions-test.ts +1 -1
- package/src/tests/bio-tests.ts +1 -1
- package/src/tests/detectors-tests.ts +10 -10
- package/src/tests/monomer-libraries-tests.ts +1 -1
- package/src/tests/seq-handler-splitted-tests.ts +6 -2
- package/src/tests/splitters-test.ts +6 -6
- package/src/tests/to-atomic-level-tests.ts +21 -14
- package/src/tests/to-atomic-level-ui-tests.ts +75 -35
- package/src/tests/utils.ts +2 -2
- package/src/utils/cell-renderer-custom.ts +62 -0
- package/src/utils/cell-renderer.ts +58 -126
- package/src/utils/cyclized.ts +28 -14
- package/src/utils/dimerized.ts +0 -2
- package/src/utils/helm-to-molfile/converter/converter.ts +75 -54
- package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +2 -2
- package/src/utils/helm-to-molfile/converter/polymer.ts +23 -16
- package/src/utils/helm-to-molfile/converter/types.ts +0 -10
- package/src/utils/helm-to-molfile/utils.ts +10 -7
- package/src/utils/monomer-cell-renderer.ts +8 -4
- package/src/utils/monomer-lib/lib-manager.ts +2 -2
- package/src/utils/monomer-lib/monomer-colors.ts +68 -0
- package/src/utils/monomer-lib/monomer-lib-base.ts +165 -0
- package/src/utils/monomer-lib/monomer-lib.ts +19 -68
- package/src/utils/monomer-lib/web-editor-monomer-dummy.ts +121 -0
- package/src/utils/monomer-lib/web-editor-monomer-of-library.ts +102 -0
- package/src/utils/save-as-fasta.ts +1 -1
- package/src/utils/seq-helper/seq-helper.ts +20 -49
- package/src/utils/sequence-to-mol.ts +24 -28
- package/src/viewers/web-logo-viewer.ts +2 -1
- package/src/widgets/composition-analysis-widget.ts +4 -3
- package/src/widgets/representations.ts +8 -10
- package/dist/248.js +0 -2
- package/dist/248.js.map +0 -1
- package/src/utils/cell-renderer-consts.ts +0 -31
package/src/tests/utils.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {asRenderer, IRenderer, isRenderer} from '@datagrok-libraries/bio/src/typ
|
|
|
7
7
|
import {startDockerContainer} from '../utils/docker';
|
|
8
8
|
|
|
9
9
|
import {_package} from '../package-test';
|
|
10
|
-
import {CellRendererBackBase,
|
|
10
|
+
import {CellRendererBackBase, getGridCellColTemp} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
11
11
|
|
|
12
12
|
export async function loadFileAsText(name: string): Promise<string> {
|
|
13
13
|
return await _package.files.readAsText(name);
|
|
@@ -47,7 +47,7 @@ export async function awaitGrid(grid: DG.Grid, timeout: number = 5000): Promise<
|
|
|
47
47
|
if (gridCol) {
|
|
48
48
|
const gridCell = grid.cell(gridCol.name, 0);
|
|
49
49
|
const [_gridCol, _tableCol, temp] =
|
|
50
|
-
|
|
50
|
+
getGridCellColTemp<void, CellRendererBackBase<void>>(gridCell);
|
|
51
51
|
|
|
52
52
|
const renderer = asRenderer(temp.rendererBack);
|
|
53
53
|
if (renderer) await renderer.awaitRendered();
|
|
@@ -0,0 +1,62 @@
|
|
|
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 {getGridCellColTemp, CellRendererBackBase} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
6
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
7
|
+
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
|
+
|
|
9
|
+
export class MacromoleculeCustomCellRenderer extends DG.GridCellRenderer {
|
|
10
|
+
get name(): string { return 'sequence'; }
|
|
11
|
+
|
|
12
|
+
get cellType(): string { return 'sequence'; }
|
|
13
|
+
|
|
14
|
+
get defaultHeight(): number | null { return 30; }
|
|
15
|
+
|
|
16
|
+
get defaultWidth(): number | null { return 230; }
|
|
17
|
+
|
|
18
|
+
getRendererBack(gridCell: DG.GridCell): CellRendererBackBase<string> {
|
|
19
|
+
const [gridCol, tableCol, temp] = getGridCellColTemp<string, any>(gridCell);
|
|
20
|
+
const sh = SeqHandler.forColumn(tableCol);
|
|
21
|
+
if (sh.notation !== NOTATION.CUSTOM)
|
|
22
|
+
throw new Error(`Unexpected notation: '${sh.notation}'.`);
|
|
23
|
+
const back = sh.getRendererBack(gridCol, tableCol);
|
|
24
|
+
return back;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override onMouseLeave(gridCell: DG.GridCell, e: MouseEvent) {
|
|
28
|
+
const back = this.getRendererBack(gridCell);
|
|
29
|
+
back.onMouseLeave(gridCell, e);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override onMouseMove(gridCell: DG.GridCell, e: MouseEvent) {
|
|
33
|
+
const back = this.getRendererBack(gridCell);
|
|
34
|
+
back.onMouseMove(gridCell, e);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override onClick(gridCell: DG.GridCell, e: MouseEvent) {
|
|
38
|
+
const back = this.getRendererBack(gridCell);
|
|
39
|
+
back.onClick(gridCell, e);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override onDoubleClick(gridCell: DG.GridCell, e: MouseEvent) {
|
|
43
|
+
const back = this.getRendererBack(gridCell);
|
|
44
|
+
back.onDoubleClick(gridCell, e);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override onKeyDown(gridCell: DG.GridCell, e: KeyboardEvent) {
|
|
48
|
+
const back = this.getRendererBack(gridCell);
|
|
49
|
+
back.onKeyDown(gridCell, e);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override onKeyPress(gridCell: DG.GridCell, e: KeyboardEvent) {
|
|
53
|
+
const back = this.getRendererBack(gridCell);
|
|
54
|
+
back.onKeyPress(gridCell, e);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell, cellStyle: DG.GridCellStyle) {
|
|
58
|
+
const back = this.getRendererBack(gridCell);
|
|
59
|
+
back.render(g, x, y, w, h, gridCell, cellStyle);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
@@ -8,7 +8,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
8
8
|
import wu from 'wu';
|
|
9
9
|
|
|
10
10
|
import {printLeftOrCentered, DrawStyle, TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
11
|
-
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
11
|
+
import {getUpdatedWidth, MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
12
12
|
import {
|
|
13
13
|
getPaletteByType,
|
|
14
14
|
monomerToShort,
|
|
@@ -20,31 +20,25 @@ import {
|
|
|
20
20
|
} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
21
21
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
22
22
|
import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
|
|
23
|
-
import {
|
|
24
|
-
import {ISeqSplitted
|
|
23
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
24
|
+
import {ISeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
25
25
|
import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
|
|
26
26
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} from '
|
|
27
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
28
|
+
import {GapOriginals} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
|
|
29
|
+
import {ISeqMonomer} from '@datagrok-libraries/bio/src/helm/types';
|
|
30
|
+
import {execMonomerHoverLinks} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
|
|
31
|
+
import {getGridCellColTemp} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
32
|
+
import {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
|
|
33
|
+
import {MmcrTemps, rendererSettingsChangedState, tempTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
|
|
34
34
|
import * as C from './constants';
|
|
35
35
|
|
|
36
36
|
import {_package, getMonomerLib} from '../package';
|
|
37
|
+
import {max} from 'rxjs/operators';
|
|
37
38
|
|
|
38
39
|
type TempType = { [tagName: string]: any };
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
-
const monomerToShortFunction: MonomerToShortFunc = monomerToShort;
|
|
42
|
-
|
|
43
|
-
function getUpdatedWidth(
|
|
44
|
-
grid: DG.Grid | null | undefined, g: CanvasRenderingContext2D, x: number, w: number, dpr: number
|
|
45
|
-
): number {
|
|
46
|
-
return !!grid ? Math.max(Math.min(grid.canvas.width / dpr - x, w)) : Math.max(g.canvas.width / dpr - x, 0);
|
|
47
|
-
}
|
|
41
|
+
export const monomerToShortFunction: MonomerToShortFunc = monomerToShort;
|
|
48
42
|
|
|
49
43
|
export function processSequence(subParts: string[]): [string[], boolean] {
|
|
50
44
|
const simplified = !wu.enumerate(subParts).some(([amino, index]) =>
|
|
@@ -65,12 +59,10 @@ export function processSequence(subParts: string[]): [string[], boolean] {
|
|
|
65
59
|
}
|
|
66
60
|
|
|
67
61
|
type RendererGridCellTemp = {
|
|
68
|
-
[
|
|
62
|
+
[MmcrTemps.monomerPlacer]: MonomerPlacer
|
|
69
63
|
}
|
|
70
64
|
|
|
71
65
|
export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
72
|
-
private padding: number = 5;
|
|
73
|
-
|
|
74
66
|
get name(): string { return 'sequence'; }
|
|
75
67
|
|
|
76
68
|
get cellType(): string { return 'sequence'; }
|
|
@@ -85,13 +77,15 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
85
77
|
gridCell.grid.invalidate();
|
|
86
78
|
}
|
|
87
79
|
|
|
88
|
-
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
80
|
+
override onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
81
|
+
if (gridCell.tableRowIndex == null) return;
|
|
82
|
+
|
|
89
83
|
// if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
|
|
90
84
|
// return;
|
|
91
85
|
|
|
92
86
|
const [_gridCol, tableCol, temp] =
|
|
93
|
-
|
|
94
|
-
const seqColTemp: MonomerPlacer = temp
|
|
87
|
+
getGridCellColTemp<string, MonomerPlacer>(gridCell);
|
|
88
|
+
const seqColTemp: MonomerPlacer = temp.rendererBack;
|
|
95
89
|
if (!seqColTemp) return; // Can do nothing without precalculated data
|
|
96
90
|
|
|
97
91
|
const gridCellBounds: DG.Rect = gridCell.bounds;
|
|
@@ -105,30 +99,39 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
105
99
|
const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCellBounds.x);
|
|
106
100
|
const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX, gridCellBounds.width);
|
|
107
101
|
|
|
108
|
-
const
|
|
109
|
-
.getSplitted(gridCell.tableRowIndex!)
|
|
110
|
-
if (left !== null && left <
|
|
111
|
-
const
|
|
102
|
+
const seqSS = SeqHandler.forColumn(tableCol)
|
|
103
|
+
.getSplitted(gridCell.tableRowIndex!);
|
|
104
|
+
if (left !== null && left < seqSS.length) {
|
|
105
|
+
const sh = SeqHandler.forColumn(tableCol);
|
|
106
|
+
const alphabet = sh.alphabet ?? ALPHABET.UN;
|
|
107
|
+
const seqMonomer = {
|
|
108
|
+
position: left,
|
|
109
|
+
biotype: alphabet === ALPHABET.RNA || alphabet === ALPHABET.DNA ? HelmTypes.NUCLEOTIDE : HelmTypes.AA,
|
|
110
|
+
symbol: seqSS.getCanonical(left),
|
|
111
|
+
} as ISeqMonomer;
|
|
112
112
|
const tooltipElements: HTMLElement[] = [];
|
|
113
|
-
let monomerDiv = seqColTemp._monomerStructureMap[
|
|
113
|
+
let monomerDiv = seqColTemp._monomerStructureMap[seqMonomer.symbol];
|
|
114
114
|
if (!monomerDiv || true) {
|
|
115
|
-
monomerDiv = seqColTemp._monomerStructureMap[
|
|
116
|
-
const sh = SeqHandler.forColumn(tableCol);
|
|
117
|
-
const alphabet = sh.alphabet ?? ALPHABET.UN;
|
|
118
|
-
const polymerType = alphabetPolymerTypes[alphabet as ALPHABET];
|
|
119
|
-
|
|
115
|
+
monomerDiv = seqColTemp._monomerStructureMap[seqMonomer.symbol] = (() => {
|
|
120
116
|
const lib: IMonomerLib | null = getMonomerLib();
|
|
121
|
-
return lib ? lib.getTooltip(
|
|
117
|
+
return lib ? lib.getTooltip(seqMonomer.biotype, seqMonomer.symbol) : ui.divText('Monomer library is not available');
|
|
122
118
|
})();
|
|
123
119
|
}
|
|
124
120
|
tooltipElements.push(monomerDiv);
|
|
125
121
|
ui.tooltip.show(ui.divV(tooltipElements), e.x + 16, e.y + 16);
|
|
122
|
+
|
|
123
|
+
execMonomerHoverLinks(gridCell, seqMonomer);
|
|
126
124
|
} else {
|
|
127
125
|
//
|
|
128
126
|
ui.tooltip.hide();
|
|
127
|
+
execMonomerHoverLinks(gridCell, null);
|
|
129
128
|
}
|
|
130
129
|
}
|
|
131
130
|
|
|
131
|
+
override onMouseLeave(gridCell: DG.GridCell, e: MouseEvent) {
|
|
132
|
+
execMonomerHoverLinks(gridCell, null);
|
|
133
|
+
}
|
|
134
|
+
|
|
132
135
|
/**
|
|
133
136
|
* Cell renderer function.
|
|
134
137
|
*
|
|
@@ -147,9 +150,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
147
150
|
): void {
|
|
148
151
|
const logPrefix: string = 'MacromoleculeSequenceCellRenderer.render()';
|
|
149
152
|
|
|
150
|
-
const dpr = window.devicePixelRatio;
|
|
151
153
|
const [gridCol, tableCol, _temp] =
|
|
152
|
-
|
|
154
|
+
getGridCellColTemp<string, MonomerPlacer>(gridCell);
|
|
153
155
|
if (!tableCol) return;
|
|
154
156
|
const tableColTemp: TempType = tableCol.temp;
|
|
155
157
|
|
|
@@ -162,13 +164,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
162
164
|
const v = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
|
|
163
165
|
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
164
166
|
}
|
|
165
|
-
if (
|
|
166
|
-
const v = tableColTemp[
|
|
167
|
+
if (MmcrTemps.maxMonomerLength in tableColTemp) {
|
|
168
|
+
const v = tableColTemp[MmcrTemps.maxMonomerLength];
|
|
167
169
|
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
const [_gc, _tc, temp] =
|
|
171
|
-
|
|
173
|
+
getGridCellColTemp<string, MonomerPlacer>(gridCell);
|
|
172
174
|
let seqColTemp: MonomerPlacer = temp.rendererBack;
|
|
173
175
|
if (!seqColTemp) {
|
|
174
176
|
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
|
|
@@ -182,91 +184,19 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
182
184
|
});
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
196
|
-
tableCol.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.false;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
200
|
-
seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!, w);
|
|
201
|
-
const _maxIndex = maxLengthWords.length;
|
|
202
|
-
|
|
203
|
-
const value: any = gridCell.cell.value;
|
|
204
|
-
const rowIdx = gridCell.cell.rowIndex;
|
|
205
|
-
const paletteType = tableCol.getTag(bioTAGS.alphabet);
|
|
206
|
-
const minDistanceRenderer = 50;
|
|
207
|
-
w = getUpdatedWidth(gridCol?.grid, g, x, w, dpr);
|
|
208
|
-
g.beginPath();
|
|
209
|
-
g.rect(x + this.padding, y + this.padding, w - this.padding - 1, h - this.padding * 2);
|
|
210
|
-
g.clip();
|
|
211
|
-
g.font = '12px monospace';
|
|
212
|
-
g.textBaseline = 'top';
|
|
213
|
-
|
|
214
|
-
//TODO: can this be replaced/merged with splitSequence?
|
|
215
|
-
const units = tableCol.meta.units;
|
|
216
|
-
const aligned: string = tableCol.getTag(bioTAGS.aligned);
|
|
217
|
-
|
|
218
|
-
const palette = getPaletteByType(paletteType);
|
|
219
|
-
|
|
220
|
-
const separator = tableCol.getTag(bioTAGS.separator) ?? '';
|
|
221
|
-
const minMonWidth = seqColTemp.props.separatorWidth + 1 * seqColTemp.props.monomerCharWidth;
|
|
222
|
-
const splitLimit = Math.ceil(w / minMonWidth);
|
|
223
|
-
const sh = SeqHandler.forColumn(tableCol);
|
|
224
|
-
|
|
225
|
-
const tempReferenceSequence: string | null = tableColTemp[tempTAGS.referenceSequence];
|
|
226
|
-
const tempCurrentWord: string | null = tableColTemp[tempTAGS.currentWord];
|
|
227
|
-
if (tempCurrentWord && tableCol?.dataFrame?.currentRowIdx === -1)
|
|
228
|
-
tableColTemp[tempTAGS.currentWord] = null;
|
|
229
|
-
|
|
230
|
-
const referenceSequence: string[] = (() => {
|
|
231
|
-
// @ts-ignore
|
|
232
|
-
const splitterFunc: SplitterFunc = sh.getSplitter(splitLimit);
|
|
233
|
-
return wu(splitterFunc(
|
|
234
|
-
((tempReferenceSequence != null) && (tempReferenceSequence != '')) ?
|
|
235
|
-
tempReferenceSequence : tempCurrentWord ?? '').originals).toArray();
|
|
236
|
-
})();
|
|
237
|
-
|
|
238
|
-
const subParts: ISeqSplitted = sh.getSplitted(rowIdx);
|
|
239
|
-
/* let x1 = x; */
|
|
240
|
-
let color = undefinedColor;
|
|
241
|
-
let drawStyle = DrawStyle.classic;
|
|
242
|
-
|
|
243
|
-
if (aligned && aligned.includes('MSA') && units == NOTATION.SEPARATOR)
|
|
244
|
-
drawStyle = DrawStyle.MSA;
|
|
245
|
-
|
|
246
|
-
const visibleSeqLength = Math.min(subParts.length, splitLimit);
|
|
247
|
-
for (let posIdx: number = 0; posIdx < visibleSeqLength; ++posIdx) {
|
|
248
|
-
const amino: string = subParts.getOriginal(posIdx);
|
|
249
|
-
color = palette.get(amino);
|
|
250
|
-
g.fillStyle = undefinedColor;
|
|
251
|
-
const last = posIdx === subParts.length - 1;
|
|
252
|
-
/*x1 = */
|
|
253
|
-
const opts = {
|
|
254
|
-
color: color, pivot: 0, left: true, transparencyRate: 1.0, separator: separator, last: last,
|
|
255
|
-
drawStyle: drawStyle, maxWord: maxLengthWordsSum, wordIdx: posIdx, gridCell: gridCell,
|
|
256
|
-
referenceSequence: referenceSequence, maxLengthOfMonomer: maxLengthOfMonomer,
|
|
257
|
-
monomerTextSizeMap: seqColTemp._monomerLengthMap, logger: _package.logger
|
|
258
|
-
};
|
|
259
|
-
printLeftOrCentered(g, amino, x + this.padding, y, w, h, opts);
|
|
260
|
-
if (minDistanceRenderer > w) break;
|
|
261
|
-
}
|
|
262
|
-
} catch (err: any) {
|
|
263
|
-
const [errMsg, errStack] = errInfo(err);
|
|
264
|
-
seqColTemp.logger.error(errMsg, undefined, errStack);
|
|
265
|
-
seqColTemp.errors.push(err);
|
|
266
|
-
//throw err; // Do not throw to prevent disabling renderer
|
|
267
|
-
} finally {
|
|
268
|
-
g.restore();
|
|
187
|
+
if (
|
|
188
|
+
tableCol.temp[MmcrTemps.rendererSettingsChanged] === rendererSettingsChangedState.true ||
|
|
189
|
+
seqColTemp.monomerLengthLimit != maxLengthOfMonomer
|
|
190
|
+
) {
|
|
191
|
+
gapLength = tableColTemp[MmcrTemps.gapLength] as number ?? gapLength;
|
|
192
|
+
// this event means that the mm renderer settings have changed,
|
|
193
|
+
// particularly monomer representation and max width.
|
|
194
|
+
seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
|
|
195
|
+
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
196
|
+
tableCol.temp[MmcrTemps.rendererSettingsChanged] = rendererSettingsChangedState.false;
|
|
269
197
|
}
|
|
198
|
+
|
|
199
|
+
seqColTemp.render(g, x, y, w, h, gridCell, _cellStyle);
|
|
270
200
|
}
|
|
271
201
|
}
|
|
272
202
|
|
|
@@ -306,8 +236,10 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
|
306
236
|
//TODO: can this be replaced/merged with splitSequence?
|
|
307
237
|
const [s1, s2] = s.split('#');
|
|
308
238
|
const splitter = getSplitter(units, separator);
|
|
309
|
-
const
|
|
310
|
-
const
|
|
239
|
+
const s1SS = splitter(s1);
|
|
240
|
+
const s2SS = splitter(s2);
|
|
241
|
+
const subParts1 = wu.count(0).take(s1SS.length).map((posIdx) => s1SS.getCanonical(posIdx)).toArray();
|
|
242
|
+
const subParts2 = wu.count(0).take(s2SS.length).map((posIdx) => s2SS.getCanonical(posIdx)).toArray();
|
|
311
243
|
drawMoleculeDifferenceOnCanvas(g, x, y, w, h, subParts1, subParts2, units);
|
|
312
244
|
}
|
|
313
245
|
}
|
package/src/utils/cyclized.ts
CHANGED
|
@@ -2,11 +2,20 @@ 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
4
|
|
|
5
|
-
import
|
|
5
|
+
import wu from 'wu';
|
|
6
|
+
|
|
7
|
+
import {INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc}
|
|
6
8
|
from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
7
9
|
import {getSplitterWithSeparator, StringListSeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
|
|
8
|
-
import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
9
10
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
11
|
+
import {CellRendererBackBase} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
12
|
+
import {GAP_SYMBOL, GapOriginals} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
|
|
13
|
+
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
14
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
15
|
+
|
|
16
|
+
import {monomerToShortFunction} from './cell-renderer';
|
|
17
|
+
|
|
18
|
+
import {_package} from '../package';
|
|
10
19
|
|
|
11
20
|
export class CyclizedNotationProvider implements INotationProvider {
|
|
12
21
|
private readonly separatorSplitter: SplitterFunc;
|
|
@@ -21,7 +30,9 @@ export class CyclizedNotationProvider implements INotationProvider {
|
|
|
21
30
|
|
|
22
31
|
private _splitter(seq: string): ISeqSplitted {
|
|
23
32
|
const baseSS: ISeqSplitted = this.separatorSplitter(seq);
|
|
24
|
-
return new CyclizedSeqSplitted(
|
|
33
|
+
return new CyclizedSeqSplitted(
|
|
34
|
+
wu.count(0).take(baseSS.length).map((p) => baseSS.getOriginal(p)).toArray(),
|
|
35
|
+
GapOriginals[NOTATION.SEPARATOR]);
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
public async getHelm(seqCol: DG.Column<string>, options?: any): Promise<DG.Column<string>> {
|
|
@@ -38,23 +49,26 @@ export class CyclizedNotationProvider implements INotationProvider {
|
|
|
38
49
|
const resHelmCol = (await editorFunc.prepare({call: ptConvertCall}).call()).getOutputParamValue() as DG.Column<string>;
|
|
39
50
|
return resHelmCol;
|
|
40
51
|
}
|
|
52
|
+
|
|
53
|
+
public createCellRendererBack(gridCol: DG.GridColumn | null, tableCol: DG.Column<string>): CellRendererBackBase<string> {
|
|
54
|
+
let maxLengthOfMonomer: number = (_package.properties ? _package.properties.maxMonomerLength : 4) ?? 50;
|
|
55
|
+
return new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
|
|
56
|
+
() => {
|
|
57
|
+
const sh = SeqHandler.forColumn(tableCol);
|
|
58
|
+
return {
|
|
59
|
+
seqHandler: sh,
|
|
60
|
+
monomerCharWidth: 7,
|
|
61
|
+
separatorWidth: 11,
|
|
62
|
+
monomerToShort: monomerToShortFunction,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
41
66
|
}
|
|
42
67
|
|
|
43
68
|
/** Gets canonical monomers for original ones with cyclization marks */
|
|
44
69
|
export class CyclizedSeqSplitted extends StringListSeqSplitted {
|
|
45
70
|
private readonly seqCList: (string | null)[];
|
|
46
71
|
|
|
47
|
-
private _canonicals: string[] | null = null;
|
|
48
|
-
override get canonicals(): SeqSplittedBase {
|
|
49
|
-
if (!this._canonicals) {
|
|
50
|
-
const len = this.length;
|
|
51
|
-
this._canonicals = new Array<string>(len);
|
|
52
|
-
for (let posIdx = 0; posIdx < len; ++posIdx)
|
|
53
|
-
this._canonicals[posIdx] = this.getCanonical(posIdx);
|
|
54
|
-
}
|
|
55
|
-
return this._canonicals;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
72
|
override getCanonical(posIdx: number): string {
|
|
59
73
|
if (this.isGap(posIdx)) return GAP_SYMBOL;
|
|
60
74
|
|
package/src/utils/dimerized.ts
CHANGED
|
@@ -2,8 +2,6 @@ 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
4
|
|
|
5
|
-
import {GAP_SYMBOL, INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc}
|
|
6
|
-
from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
7
5
|
import {CyclizedNotationProvider} from './cyclized';
|
|
8
6
|
|
|
9
7
|
|
|
@@ -4,37 +4,39 @@ import * as OCL from 'openchemlib/full';
|
|
|
4
4
|
|
|
5
5
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
6
6
|
import {RDModule, RDMol} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
7
|
-
import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
|
|
7
|
+
import {IMonomerLib, IMonomerLibBase} from '@datagrok-libraries/bio/src/types/index';
|
|
8
8
|
import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
9
9
|
import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
10
|
+
import {MolfileWithMap, MonomerMap} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
10
11
|
|
|
11
12
|
import {Polymer} from './polymer';
|
|
12
13
|
import {GlobalMonomerPositionHandler} from './position-handler';
|
|
13
|
-
import {MolfileWithMap, MonomerMap} from './types';
|
|
14
14
|
|
|
15
15
|
import {_package} from '../../../package';
|
|
16
|
+
import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
export class HelmToMolfileConverter {
|
|
19
20
|
constructor(
|
|
20
|
-
private
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private helmHelper: IHelmHelper,
|
|
21
|
+
private readonly helmHelper: IHelmHelper,
|
|
22
|
+
private readonly rdKitModule: RDModule,
|
|
23
|
+
private readonly monomerLib: IMonomerLibBase
|
|
24
24
|
) { }
|
|
25
25
|
|
|
26
|
-
convertToSmiles(
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
26
|
+
convertToSmiles(helmCol: DG.Column<string>): DG.Column<string> {
|
|
27
|
+
const df = helmCol.dataFrame;
|
|
28
|
+
const smiles = this.getSmilesList(helmCol);
|
|
29
|
+
const smilesColName = `smiles(${helmCol.name})`;
|
|
30
|
+
const smilesColNameU = df ? df.columns.getUnusedName(smilesColName) : smilesColName;
|
|
31
|
+
return DG.Column.fromStrings(smilesColNameU, smiles.map((molecule) => {
|
|
30
32
|
if (molecule === null)
|
|
31
33
|
return '';
|
|
32
34
|
return molecule;
|
|
33
35
|
}));
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
private getSmilesList(
|
|
37
|
-
const molfilesV2K = this.convertToMolfileV3KColumn(
|
|
38
|
+
private getSmilesList(helmCol: DG.Column<string>): string[] {
|
|
39
|
+
const molfilesV2K = this.convertToMolfileV3KColumn(helmCol).toList();
|
|
38
40
|
const smiles = molfilesV2K.map((mol) => DG.chem.convert(mol, DG.chem.Notation.MolBlock, DG.chem.Notation.Smiles));
|
|
39
41
|
return smiles;
|
|
40
42
|
}
|
|
@@ -61,8 +63,11 @@ export class HelmToMolfileConverter {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
// @deprecated Use SeqHelper.helmToAtomicLevel
|
|
64
|
-
convertToRdKitBeautifiedMolfileColumn(
|
|
65
|
-
|
|
66
|
+
convertToRdKitBeautifiedMolfileColumn(
|
|
67
|
+
helmCol: DG.Column<string>, chiralityEngine: boolean, rdKitModule: RDModule, monomerLib: IMonomerLibBase
|
|
68
|
+
): DG.Column<string> {
|
|
69
|
+
const df = helmCol.dataFrame;
|
|
70
|
+
const molfilesV3K = this.convertToMolfileV3KColumn(helmCol).toList();
|
|
66
71
|
const beautifiedMols = molfilesV3K.map((item) => {
|
|
67
72
|
if (item === '')
|
|
68
73
|
return null;
|
|
@@ -74,11 +79,12 @@ export class HelmToMolfileConverter {
|
|
|
74
79
|
mol.straighten_depiction(true);
|
|
75
80
|
return mol;
|
|
76
81
|
});
|
|
77
|
-
const
|
|
82
|
+
const molColName = `molfile(${helmCol.name})`;
|
|
83
|
+
const molColNameU = df ? df.columns.getUnusedName(molColName) : molColName;
|
|
78
84
|
|
|
79
85
|
if (chiralityEngine)
|
|
80
|
-
return this.getMolV3000ViaOCL(beautifiedMols,
|
|
81
|
-
return DG.Column.fromStrings(
|
|
86
|
+
return this.getMolV3000ViaOCL(beautifiedMols, molColNameU);
|
|
87
|
+
return DG.Column.fromStrings(molColNameU, beautifiedMols.map((mol) => {
|
|
82
88
|
if (mol === null)
|
|
83
89
|
return '';
|
|
84
90
|
const molBlock = mol.get_v3Kmolblock();
|
|
@@ -88,71 +94,86 @@ export class HelmToMolfileConverter {
|
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
|
|
91
|
-
public convertToMolfileV3KColumn(
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
public convertToMolfileV3KColumn(
|
|
98
|
+
helmCol: DG.Column<string>
|
|
99
|
+
): DG.Column<string> {
|
|
100
|
+
const df = helmCol.dataFrame;
|
|
101
|
+
const polymerGraphColumn: DG.Column<string> = this.getPolymerGraphColumn(helmCol);
|
|
94
102
|
const molfileList = polymerGraphColumn.toList().map(
|
|
95
103
|
(pseudoMolfile: string, idx: number) => {
|
|
96
|
-
const helm =
|
|
104
|
+
const helm = helmCol.get(idx);
|
|
97
105
|
if (!helm) return '';
|
|
98
106
|
|
|
99
107
|
let resMolfileWithMap: MolfileWithMap;
|
|
100
108
|
try {
|
|
101
|
-
resMolfileWithMap = this.getPolymerMolfile(helm, pseudoMolfile
|
|
109
|
+
resMolfileWithMap = this.getPolymerMolfile(helm, pseudoMolfile);
|
|
102
110
|
} catch (err: any) {
|
|
103
111
|
const [errMsg, errStack] = errInfo(err);
|
|
104
112
|
_package.logger.error(errMsg, undefined, errStack);
|
|
105
|
-
resMolfileWithMap = MolfileWithMap.
|
|
113
|
+
resMolfileWithMap = MolfileWithMap.createEmpty();
|
|
106
114
|
}
|
|
107
115
|
return resMolfileWithMap.molfile;
|
|
108
116
|
});
|
|
109
|
-
const
|
|
110
|
-
const molfileColumn = DG.Column.fromList('string',
|
|
117
|
+
const molColName = getUnusedColName(df, `molfileV2K(${helmCol.name})`);
|
|
118
|
+
const molfileColumn = DG.Column.fromList('string', molColName, molfileList);
|
|
111
119
|
return molfileColumn;
|
|
112
120
|
}
|
|
113
121
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
/** Gets list of monomer molfiles */
|
|
123
|
+
public convertToMolfileV3K(helmCol: DG.Column<string>, rdKitModule: RDModule, monomerLib: IMonomerLibBase): MolfileWithMap[] {
|
|
124
|
+
const polymerGraphColumn: DG.Column<string> = this.getPolymerGraphColumn(helmCol);
|
|
125
|
+
const rowCount = helmCol.length;
|
|
126
|
+
const resList: MolfileWithMap[] = new Array<MolfileWithMap>(rowCount);
|
|
127
|
+
for (let rowIdx = 0; rowIdx < rowCount; ++rowIdx) {
|
|
128
|
+
const helm = helmCol.get(rowIdx);
|
|
129
|
+
if (!helm) {
|
|
130
|
+
resList[rowIdx] = MolfileWithMap.createEmpty();
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const pseudoMolfile = polymerGraphColumn.get(rowIdx)!;
|
|
135
|
+
let resMolfile: MolfileWithMap;
|
|
136
|
+
try {
|
|
137
|
+
resMolfile = this.getPolymerMolfile(helm, pseudoMolfile);
|
|
138
|
+
} catch (err: any) {
|
|
139
|
+
const [errMsg, errStack] = errInfo(err);
|
|
140
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
141
|
+
resMolfile = MolfileWithMap.createEmpty();
|
|
142
|
+
}
|
|
143
|
+
resList[rowIdx] = resMolfile;
|
|
144
|
+
}
|
|
132
145
|
return resList;
|
|
133
146
|
}
|
|
134
147
|
|
|
135
|
-
private getPolymerGraphColumn(): DG.Column<string> {
|
|
136
|
-
const helmStrList =
|
|
148
|
+
private getPolymerGraphColumn(helmCol: DG.Column<string>): DG.Column<string> {
|
|
149
|
+
const helmStrList = helmCol.toList();
|
|
137
150
|
const molfileList = this.helmHelper.getMolfiles(helmStrList);
|
|
138
151
|
const molfileCol = DG.Column.fromStrings('mols', molfileList);
|
|
139
152
|
return molfileCol;
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
private getPolymerMolfile(
|
|
143
|
-
helm: string,
|
|
144
|
-
polymerGraph: string,
|
|
145
|
-
rdKitModule: RDModule,
|
|
146
|
-
monomerLib: IMonomerLib
|
|
156
|
+
helm: string, polymerGraph: string
|
|
147
157
|
): MolfileWithMap {
|
|
158
|
+
const woGapsRes = this.helmHelper.removeGaps(helm);
|
|
159
|
+
const woGapsHelm = woGapsRes.resHelm;
|
|
160
|
+
const woGapsReverseMap = new Map<number, number>();
|
|
161
|
+
for (const [orgPosIdx, woGapsPosIdx] of (woGapsRes.monomerMap?.entries() ?? [])) {
|
|
162
|
+
woGapsReverseMap.set(woGapsPosIdx, orgPosIdx);
|
|
163
|
+
}
|
|
148
164
|
const globalPositionHandler = new GlobalMonomerPositionHandler(polymerGraph);
|
|
149
|
-
const
|
|
165
|
+
const woGapsPolymer = new Polymer(woGapsHelm, this.rdKitModule, this.monomerLib);
|
|
150
166
|
globalPositionHandler.monomerSymbols.forEach((monomerSymbol: string, monomerIdx: number) => {
|
|
151
167
|
const shift = globalPositionHandler.getMonomerShifts(monomerIdx);
|
|
152
|
-
|
|
168
|
+
woGapsPolymer.addMonomer(monomerSymbol, monomerIdx, shift);
|
|
153
169
|
});
|
|
154
|
-
const
|
|
155
|
-
|
|
170
|
+
const woGapsMolfile: MolfileWithMap = woGapsPolymer.compileToMolfile();
|
|
171
|
+
const orgMonomerMap = new MonomerMap();
|
|
172
|
+
for (const [woGapsPosIdx, m] of woGapsMolfile.monomers.entries()) {
|
|
173
|
+
const orgPosIdx = woGapsReverseMap.get(woGapsPosIdx)!;
|
|
174
|
+
orgMonomerMap.set(orgPosIdx, m);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return new MolfileWithMap(woGapsMolfile.molfile, orgMonomerMap);
|
|
156
178
|
}
|
|
157
179
|
}
|
|
158
|
-
|