@datagrok/bio 2.4.44 → 2.4.45

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.4.44",
8
+ "version": "2.4.45",
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",
@@ -0,0 +1,42 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ export class SplitToMonomersFunctionEditor {
6
+ tableInput: DG.InputBase;
7
+ seqColInput: DG.InputBase;
8
+
9
+ funcParamsDiv: HTMLDivElement;
10
+
11
+ get funcParams(): {} {
12
+ return {
13
+ table: this.tableInput.value!,
14
+ sequence: this.seqColInput.value!,
15
+ };
16
+ }
17
+
18
+ get paramsUI(): HTMLDivElement {
19
+ return this.funcParamsDiv;
20
+ }
21
+
22
+ constructor() {
23
+ this.tableInput = ui.tableInput('Table', grok.shell.tv.dataFrame, undefined, () => {
24
+ this.onTableInputChanged();
25
+ });
26
+ //TODO: remove when the new version of datagrok-api is available
27
+ const seqColValue = this.tableInput.value!.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
28
+ const seqColOptions = {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE};
29
+ //@ts-ignore
30
+ this.seqColInput = ui.columnInput('Sequence', this.tableInput.value!, seqColValue, null, seqColOptions);
31
+
32
+ this.funcParamsDiv = ui.inputs([
33
+ this.tableInput,
34
+ this.seqColInput,
35
+ ], {style: {minWidth: '320px'}});
36
+ }
37
+
38
+ onTableInputChanged(): void {
39
+ this.seqColInput = ui.columnInput('Sequence', this.tableInput.value!,
40
+ this.tableInput.value!.columns.bySemType(DG.SEMTYPE.MACROMOLECULE));
41
+ }
42
+ }
@@ -8,7 +8,9 @@ import './tests/detectors-tests';
8
8
  import './tests/detectors-weak-and-likely-tests';
9
9
  import './tests/detectors-benchmark-tests';
10
10
  import './tests/msa-tests';
11
- import './tests/splitters-test';
11
+
12
+ import './tests/splitters-test'; //Unhandled exceptions.exceptions : Cannot read properties of null (reading 'f')
13
+
12
14
  import './tests/monomer-libraries-tests';
13
15
  import './tests/renderers-test';
14
16
  import './tests/converters-test';
package/src/package.ts CHANGED
@@ -2,8 +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
+
5
6
  import {
6
- MacromoleculeDifferenceCellRenderer, MacromoleculeSequenceCellRenderer, MonomerCellRenderer,
7
+ MacromoleculeDifferenceCellRenderer, MacromoleculeSequenceCellRenderer,
7
8
  } from './utils/cell-renderer';
8
9
  import {VdRegionsViewer} from './viewers/vd-regions-viewer';
9
10
  import {SequenceAlignment} from './seq_align';
@@ -18,8 +19,6 @@ import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomi
18
19
  import {FastaFileHandler} from '@datagrok-libraries/bio/src/utils/fasta-handler';
19
20
  import {removeEmptyStringRows} from '@datagrok-libraries/utils/src/dataframe-utils';
20
21
 
21
- import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
22
- import * as C from './utils/constants';
23
22
  import {SequenceSimilarityViewer} from './analysis/sequence-similarity-viewer';
24
23
  import {SequenceDiversityViewer} from './analysis/sequence-diversity-viewer';
25
24
  import {substructureSearchDialog} from './substructure-search/substructure-search';
@@ -39,6 +38,7 @@ import {getMacromoleculeColumn} from './utils/ui-utils';
39
38
  import {DimReductionMethods, ITSNEOptions, IUMAPOptions} from '@datagrok-libraries/ml/src/reduce-dimensionality';
40
39
  import {SequenceSpaceFunctionEditor} from '@datagrok-libraries/ml/src/functionEditors/seq-space-editor';
41
40
  import {ActivityCliffsFunctionEditor} from '@datagrok-libraries/ml/src/functionEditors/activity-cliffs-editor';
41
+
42
42
  import {demoBio01UI} from './demo/bio01-similarity-diversity';
43
43
  import {demoBio01aUI} from './demo/bio01a-hierarchical-clustering-and-sequence-space';
44
44
  import {demoBio01bUI} from './demo/bio01b-hierarchical-clustering-and-activity-cliffs';
@@ -50,6 +50,9 @@ import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule
50
50
  import {BitArrayMetrics, BitArrayMetricsNames} from '@datagrok-libraries/ml/src/typed-metrics';
51
51
  import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
52
52
  import {WebLogoApp} from './apps/web-logo-app';
53
+ import {SplitToMonomersFunctionEditor} from './function-edtiors/split-to-monomers-editor';
54
+ import {splitToMonomersUI} from './utils/split-to-monomers';
55
+ import {MonomerCellRenderer} from './utils/monomer-cell-renderer';
53
56
 
54
57
  export const _package = new DG.Package();
55
58
 
@@ -248,7 +251,7 @@ export function SeqActivityCliffsEditor(call: DG.FuncCall) {
248
251
  ui.dialog({title: 'Activity Cliffs'})
249
252
  .add(funcEditor.paramsUI)
250
253
  .onOK(async () => {
251
- call.func.prepare(funcEditor.funcParams).call(true);
254
+ return call.func.prepare(funcEditor.funcParams).call(true);
252
255
  })
253
256
  .show();
254
257
  }
@@ -342,7 +345,7 @@ export function SequenceSpaceEditor(call: DG.FuncCall) {
342
345
  ui.dialog({title: 'Sequence Space'})
343
346
  .add(funcEditor.paramsUI)
344
347
  .onOK(async () => {
345
- call.func.prepare(funcEditor.funcParams).call(true);
348
+ return call.func.prepare(funcEditor.funcParams).call(true);
346
349
  })
347
350
  .show();
348
351
  }
@@ -364,8 +367,7 @@ export async function sequenceSpaceTopMenu(
364
367
  // Delay is required for initial function dialog to close before starting invalidating of molfiles.
365
368
  // Otherwise, dialog is freezing
366
369
  await delay(10);
367
- if (!checkInputColumnUI(macroMolecule, 'Sequence space'))
368
- return;
370
+ if (!checkInputColumnUI(macroMolecule, 'Sequence space')) return;
369
371
 
370
372
  const embedColsNames = getEmbeddingColsNames(table);
371
373
  const withoutEmptyValues = DG.DataFrame.fromColumns([macroMolecule]).clone();
@@ -586,6 +588,7 @@ export function convertDialog() {
586
588
  //name: monomerCellRenderer
587
589
  //tags: cellRenderer
588
590
  //meta.cellType: Monomer
591
+ //meta.columnTags: quality=Monomer
589
592
  //output: grid_cell_renderer result
590
593
  export function monomerCellRenderer(): MonomerCellRenderer {
591
594
  return new MonomerCellRenderer();
@@ -642,20 +645,27 @@ export async function testDetectMacromolecule(path: string): Promise<DG.DataFram
642
645
  return resDf;
643
646
  }
644
647
 
645
- //top-menu: Bio | Split to monomers
646
- //name: splitToMonomers
647
- export function splitToMonomers(): void {
648
- const col = getMacromoleculeColumn();
649
- const tempDf = splitAlignedSequences(col);
650
- const originalDf = col.dataFrame;
651
- for (const tempCol of tempDf.columns) {
652
- const newCol = originalDf.columns.add(tempCol);
653
- newCol.semType = C.SEM_TYPES.MONOMER;
654
- // TODO: GROK-
655
- //newCol.setTag(DG.TAGS.CELL_RENDERER, C.SEM_TYPES.MONOMER);
656
- newCol.setTag(bioTAGS.alphabet, col.getTag(bioTAGS.alphabet));
657
- }
658
- grok.shell.tv.grid.invalidate();
648
+ //name: SplitToMonomersEditor
649
+ //tags: editor
650
+ //input: funccall call
651
+ export function SplitToMonomersEditor(call: DG.FuncCall): void {
652
+ const funcEditor = new SplitToMonomersFunctionEditor();
653
+ ui.dialog({title: 'Split to Monomers'})
654
+ .add(funcEditor.paramsUI)
655
+ .onOK(async () => {
656
+ return call.func.prepare(funcEditor.funcParams).call(true);
657
+ })
658
+ .show();
659
+ }
660
+
661
+ //top-menu: Bio | Split to Monomers
662
+ //name: Split to Monomers
663
+ //input: dataframe table
664
+ //input: column sequence { semType: Macromolecule }
665
+ //output: dataframe result
666
+ //editor: Bio:SplitToMonomersEditor
667
+ export async function splitToMonomersTopMenu(table: DG.DataFrame, sequence: DG.Column): Promise<void> {
668
+ await splitToMonomersUI(table, sequence);
659
669
  }
660
670
 
661
671
  //name: Bio: getHelmMonomers
@@ -6,6 +6,7 @@ import {after, before, category, test, expect, expectArray, delay} from '@datagr
6
6
  import * as C from '../utils/constants';
7
7
  import {_package, getHelmMonomers} from '../package';
8
8
  import {TAGS as bioTAGS, splitterAsFasta, splitterAsHelm} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
+ import {splitToMonomersUI} from '../utils/split-to-monomers';
9
10
 
10
11
 
11
12
  category('splitters', async () => {
@@ -77,14 +78,15 @@ category('splitters', async () => {
77
78
  seqCol.semType = semType;
78
79
  seqCol.setTag(bioTAGS.aligned, C.MSA);
79
80
 
80
- const _tv: DG.TableView = grok.shell.addTableView(df);
81
- await delay(500); // needed to account for table adding
82
- // call to calculate 'cell.renderer' tag
83
- await grok.data.detectSemanticTypes(df);
81
+ const newDf = await splitToMonomersUI(df, seqCol);
82
+ expect(newDf.columns.names().includes('17'), true);
84
83
 
85
- await grok.functions.call('Bio:splitToMonomers');
86
- expect(df.columns.names().includes('17'), true);
87
- });
84
+ // TODO: Check cell.renderer for columns of monomers
85
+ // const _tv: DG.TableView = grok.shell.addTableView(df);
86
+ // await delay(500); // needed to account for table adding
87
+ // // call to calculate 'cell.renderer' tag
88
+ // await grok.data.detectSemanticTypes(df);
89
+ }, {skipReason: 'GROK-13300'});
88
90
 
89
91
  test('getHelmMonomers', async () => {
90
92
  const df: DG.DataFrame = DG.DataFrame.fromCsv(
@@ -3,9 +3,8 @@ 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 C from './constants';
7
6
  import {
8
- ALIGNMENT,
7
+ ALIGNMENT, ALPHABET,
9
8
  getPaletteByType,
10
9
  getSplitter,
11
10
  monomerToShort,
@@ -15,6 +14,10 @@ import {
15
14
  } from '@datagrok-libraries/bio/src/utils/macromolecule';
16
15
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
17
16
  import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
17
+ import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
18
+
19
+ import {_package, getMonomerLibHelper} from '../package';
20
+ import * as C from './constants';
18
21
 
19
22
  const enum tempTAGS {
20
23
  referenceSequence = 'reference-sequence',
@@ -215,58 +218,6 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
215
218
  }
216
219
  }
217
220
 
218
- export class MonomerCellRenderer extends DG.GridCellRenderer {
219
- get name(): string { return C.SEM_TYPES.MONOMER; }
220
-
221
- get cellType(): string { return C.SEM_TYPES.MONOMER; }
222
-
223
- get defaultHeight(): number { return 15; }
224
-
225
- get defaultWidth(): number { return 30; }
226
-
227
- /**
228
- * Cell renderer function.
229
- *
230
- * @param {CanvasRenderingContext2D} g Canvas rendering context.
231
- * @param {number} x x coordinate on the canvas.
232
- * @param {number} y y coordinate on the canvas.
233
- * @param {number} w width of the cell.
234
- * @param {number} h height of the cell.
235
- * @param {DG.GridCell} gridCell Grid cell.
236
- * @param {DG.GridCellStyle} _cellStyle Cell style.
237
- */
238
- render(
239
- g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
240
- _cellStyle: DG.GridCellStyle): void {
241
- g.font = `12px monospace`;
242
- g.textBaseline = 'middle';
243
- g.textAlign = 'center';
244
-
245
- const palette = getPaletteByType(gridCell.cell.column.getTag(bioTAGS.alphabet));
246
- const s: string = gridCell.cell.value;
247
- if (!s)
248
- return;
249
- const color = palette.get(s);
250
-
251
- g.fillStyle = color;
252
- g.fillText(monomerToShort(s, 3), x + (w / 2), y + (h / 2), w);
253
- }
254
-
255
- svgMolOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
256
-
257
- onMouseEnter(gridCell: DG.GridCell, e: MouseEvent) {
258
- super.onMouseEnter(gridCell, e);
259
-
260
- // TODO: Display monomer structure within tooltip
261
- // const monomerName = gridCell.cell.value;
262
- // const mw = getMonomerWorksInstance();
263
- // // TODO: Display monomer structure in Tooltip
264
- // const nameDiv = ui.div(monomerName);
265
- // const molDiv = grok.chem.svgMol(monomerMol, undefined, undefined, svgMolOptions);
266
- //
267
- // ui.tooltip.show(ui.divV([nameDiv, molEl,]), x, y);
268
- }
269
- }
270
221
 
271
222
  export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
272
223
  get name(): string { return 'MacromoleculeDifferenceCR'; }
@@ -0,0 +1,100 @@
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 {ALPHABET, getPaletteByType, monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
+ import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
7
+ import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
8
+
9
+ import {getMonomerLibHelper} from '../package';
10
+ import * as C from './constants';
11
+
12
+ const Tags = new class {
13
+ tooltipHandlerTemp = 'tooltip-handler.Monomer';
14
+ }();
15
+
16
+ const svgMolOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
17
+
18
+ export class MonomerTooltipHandler {
19
+ private readonly grid: DG.Grid;
20
+
21
+ constructor(grid: DG.Grid) {
22
+ this.grid = grid;
23
+ this.grid.onCellTooltip(this.onCellTooltip.bind(this));
24
+ }
25
+
26
+ private onCellTooltip(gridCell: DG.GridCell, x: number, y: number): any {
27
+ if (gridCell.grid.dart != this.grid.dart || !gridCell.tableColumn || !gridCell.isTableCell ||
28
+ gridCell.tableColumn.semType != 'Monomer') return false;
29
+
30
+ const alphabet = gridCell.tableColumn.getTag(bioTAGS.alphabet);
31
+ const monomerName = gridCell.cell.value;
32
+ const mw = new MonomerWorks(getMonomerLibHelper().getBioLib());
33
+ const monomerType: string = (alphabet === ALPHABET.DNA || alphabet === ALPHABET.RNA) ? 'RNA' :
34
+ alphabet === ALPHABET.PT ? 'PEPTIDE' : 'PEPTIDE';
35
+
36
+ const monomerMol: string | null = mw.getCappedRotatedMonomer(monomerType, monomerName);
37
+ const nameDiv = ui.div(monomerName);
38
+ const molDiv = !monomerMol ? null :
39
+ grok.chem.svgMol(monomerMol, undefined, undefined, svgMolOptions);
40
+
41
+ const canvasClientRect = gridCell.grid.canvas.getBoundingClientRect();
42
+ const x1 = gridCell.bounds.right + canvasClientRect.left - 4;
43
+ const y1 = gridCell.bounds.bottom + canvasClientRect.top - 4;
44
+ ui.tooltip.show(ui.divV([nameDiv, ...(molDiv ? [molDiv] : [])]), x1, y1);
45
+
46
+ return true; // To prevent default tooltip behaviour
47
+ }
48
+
49
+ public static getOrCreate(grid: DG.Grid): MonomerTooltipHandler {
50
+ const gridTemp: { [tempName: string]: any } = grid.dataFrame.temp;
51
+ if (!(Tags.tooltipHandlerTemp in gridTemp)) {
52
+ gridTemp[Tags.tooltipHandlerTemp] = new MonomerTooltipHandler(grid);
53
+ grid.temp = gridTemp;
54
+ }
55
+ return gridTemp[Tags.tooltipHandlerTemp];
56
+ }
57
+ }
58
+
59
+ export class MonomerCellRenderer extends DG.GridCellRenderer {
60
+ get name(): string { return C.SEM_TYPES.MONOMER; }
61
+
62
+ get cellType(): string { return C.SEM_TYPES.MONOMER; }
63
+
64
+ get defaultHeight(): number { return 15; }
65
+
66
+ get defaultWidth(): number { return 30; }
67
+
68
+ /**
69
+ * Cell renderer function.
70
+ *
71
+ * @param {CanvasRenderingContext2D} g Canvas rendering context.
72
+ * @param {number} x x coordinate on the canvas.
73
+ * @param {number} y y coordinate on the canvas.
74
+ * @param {number} w width of the cell.
75
+ * @param {number} h height of the cell.
76
+ * @param {DG.GridCell} gridCell Grid cell.
77
+ * @param {DG.GridCellStyle} _cellStyle Cell style.
78
+ */
79
+ render(
80
+ g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
81
+ _cellStyle: DG.GridCellStyle
82
+ ): void {
83
+ if (gridCell.gridRow < 0) return;
84
+ MonomerTooltipHandler.getOrCreate(gridCell.grid);
85
+
86
+
87
+ g.font = `12px monospace`;
88
+ g.textBaseline = 'middle';
89
+ g.textAlign = 'center';
90
+
91
+ const palette = getPaletteByType(gridCell.cell.column.getTag(bioTAGS.alphabet));
92
+ const s: string = gridCell.cell.value;
93
+ if (!s)
94
+ return;
95
+ const color = palette.get(s);
96
+
97
+ g.fillStyle = color;
98
+ g.fillText(monomerToShort(s, 3), x + (w / 2), y + (h / 2), w);
99
+ }
100
+ }
@@ -0,0 +1,29 @@
1
+ import {delay} from '@datagrok-libraries/utils/src/test';
2
+ import {checkInputColumnUI} from './check-input-column';
3
+ import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
4
+ import * as C from './constants';
5
+ import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
6
+ import * as grok from 'datagrok-api/grok';
7
+ import * as DG from 'datagrok-api/dg';
8
+
9
+
10
+ export async function splitToMonomersUI(table: DG.DataFrame, seqCol: DG.Column<string>): Promise<DG.DataFrame> {
11
+ // Delay is required for initial function dialog to close before starting invalidating of molfiles.
12
+ // Otherwise, dialog is freezing
13
+ await delay(10);
14
+ if (!checkInputColumnUI(seqCol, 'Sequence space')) return table;
15
+
16
+ const tempDf = splitAlignedSequences(seqCol);
17
+ const originalDf = seqCol.dataFrame;
18
+ for (const tempCol of tempDf.columns) {
19
+ // TODO: GROK-11212
20
+ // tempCol.setTag(DG.TAGS.CELL_RENDERER, C.SEM_TYPES.MONOMER);
21
+ tempCol.semType = C.SEM_TYPES.MONOMER;
22
+ tempCol.setTag(bioTAGS.alphabet, seqCol.getTag(bioTAGS.alphabet));
23
+ }
24
+ // Create the new data frame to enable platform to setup cell renderers
25
+ const newDf = originalDf.join(tempDf, [], [], undefined, undefined, DG.JOIN_TYPE.LEFT, false);
26
+ grok.shell.addTableView(newDf);
27
+
28
+ return newDf;
29
+ }