@datagrok/bio 2.4.44 → 2.4.46

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,16 +5,24 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.4.44",
8
+ "version": "2.4.46",
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",
12
12
  "url": "https://github.com/datagrok-ai/public.git",
13
13
  "directory": "packages/Bio"
14
14
  },
15
+ "properties": [
16
+ {
17
+ "name": "MaxMonomerLength",
18
+ "propertyType": "int",
19
+ "defaultValue": 3,
20
+ "nullable": false
21
+ }
22
+ ],
15
23
  "dependencies": {
16
24
  "@biowasm/aioli": "^3.1.0",
17
- "@datagrok-libraries/bio": "^5.32.3",
25
+ "@datagrok-libraries/bio": "^5.32.4",
18
26
  "@datagrok-libraries/chem-meta": "^1.0.1",
19
27
  "@datagrok-libraries/ml": "^6.3.39",
20
28
  "@datagrok-libraries/tutorials": "^1.3.2",
@@ -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';
@@ -0,0 +1,40 @@
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 {Observable, Subject} from 'rxjs';
6
+ import {ObjectPropertyBag} from 'datagrok-api/dg';
7
+
8
+ /** Names of package properties/settings declared in properties section of {@link './package.json'} */
9
+ export const enum BioPackagePropertiesNames {
10
+ MaxMonomerLength = 'MaxMonomerLength',
11
+ }
12
+
13
+
14
+ export class BioPackageProperties extends Map<string, any> {
15
+
16
+ private _onPropertyChanged: Subject<string> = new Subject<string>();
17
+ public get onPropertyChanged(): Observable<string> { return this._onPropertyChanged; }
18
+
19
+ /** Monomer name maximum length displayed in short mode. */
20
+ public get maxMonomerLength(): number {
21
+ return super.get(BioPackagePropertiesNames.MaxMonomerLength) as unknown as number;
22
+ }
23
+
24
+ public set maxMonomerLength(value: number) {
25
+ super.set(BioPackagePropertiesNames.MaxMonomerLength, value as unknown as object);
26
+ this._onPropertyChanged.next(BioPackagePropertiesNames.MaxMonomerLength);
27
+ }
28
+
29
+ constructor(source: any) {
30
+ super(Object.entries(source));
31
+ }
32
+ }
33
+
34
+ export class BioPackage extends DG.Package {
35
+ private _properties: BioPackageProperties;
36
+ /** Package properties/settings declared in properties section of {@link './package.json'} */
37
+ public get properties(): BioPackageProperties { return this._properties; };
38
+
39
+ public set properties(value: BioPackageProperties) { this._properties = value; }
40
+ }
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';
@@ -13,13 +14,11 @@ import {
13
14
  createLinesGrid, createPropPanelElement, createTooltipElement, getChemSimilaritiesMatrix,
14
15
  } from './analysis/sequence-activity-cliffs';
15
16
  import {convert} from './utils/convert';
16
- import {getMacroMolColumnPropertyPanel} from './widgets/representations';
17
+ import {getMacromoleculeColumnPropertyPanel} from './widgets/representations';
17
18
  import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
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,8 +50,15 @@ 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';
56
+ import {BioPackage, BioPackageProperties} from './package-types';
57
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
58
+ import {ObjectPropertyBag} from 'datagrok-api/dg';
59
+ import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
53
60
 
54
- export const _package = new DG.Package();
61
+ export const _package = new BioPackage();
55
62
 
56
63
  // /** Avoid reassinging {@link monomerLib} because consumers subscribe to {@link IMonomerLib.onChanged} event */
57
64
  // let monomerLib: MonomerLib | null = null;
@@ -79,11 +86,20 @@ export class SeqPaletteCustom implements SeqPalette {
79
86
 
80
87
  //tags: init
81
88
  export async function initBio() {
82
- await MonomerLibHelper.instance.loadLibraries();
89
+ let module: RDModule;
90
+ await Promise.all([
91
+ (async () => { await MonomerLibHelper.instance.loadLibraries(); })(),
92
+ (async () => { module = await grok.functions.call('Chem:getRdKitModule'); })(),
93
+ (async () => {
94
+ const pkgProps = await _package.getProperties();
95
+ const bioPkgProps = new BioPackageProperties(pkgProps);
96
+ _package.properties = bioPkgProps;
97
+ })(),
98
+ ]);
99
+
83
100
  const monomerLib = MonomerLibHelper.instance.getBioLib();
84
101
  const monomers: string[] = [];
85
102
  const logPs: number[] = [];
86
- const module = await grok.functions.call('Chem:getRdKitModule');
87
103
 
88
104
  const series = monomerLib!.getMonomerMolsByPolymerType('PEPTIDE')!;
89
105
  Object.keys(series).forEach((symbol) => {
@@ -170,6 +186,21 @@ export async function libraryPanel(_seqColumn: DG.Column): Promise<DG.Widget> {
170
186
  return new DG.Widget(ui.divV([inputsForm, ui.div(filesButton)]));
171
187
  }
172
188
 
189
+ // -- Package settings editor --
190
+
191
+ //name: packageSettingsEditor
192
+ //description: The database connection
193
+ //tags: packageSettingsEditor
194
+ //input: object propList
195
+ //output: widget result
196
+ export function packageSettingsEditor(propList: DG.Property[]): DG.Widget {
197
+ const widget = new PackageSettingsEditorWidget(propList);
198
+ widget.init().then(); // Ignore promise returned
199
+ return widget;
200
+ }
201
+
202
+ // -- Cell renderers --
203
+
173
204
  //name: fastaSequenceCellRenderer
174
205
  //tags: cellRenderer
175
206
  //meta.cellType: sequence
@@ -184,7 +215,7 @@ export function fastaSequenceCellRenderer(): MacromoleculeSequenceCellRenderer {
184
215
  //tags: panel
185
216
  //output: widget result
186
217
  export function macroMolColumnPropertyPanel(molColumn: DG.Column): DG.Widget {
187
- return getMacroMolColumnPropertyPanel(molColumn);
218
+ return getMacromoleculeColumnPropertyPanel(molColumn);
188
219
  }
189
220
 
190
221
  //name: separatorSequenceCellRenderer
@@ -248,7 +279,7 @@ export function SeqActivityCliffsEditor(call: DG.FuncCall) {
248
279
  ui.dialog({title: 'Activity Cliffs'})
249
280
  .add(funcEditor.paramsUI)
250
281
  .onOK(async () => {
251
- call.func.prepare(funcEditor.funcParams).call(true);
282
+ return call.func.prepare(funcEditor.funcParams).call(true);
252
283
  })
253
284
  .show();
254
285
  }
@@ -342,7 +373,7 @@ export function SequenceSpaceEditor(call: DG.FuncCall) {
342
373
  ui.dialog({title: 'Sequence Space'})
343
374
  .add(funcEditor.paramsUI)
344
375
  .onOK(async () => {
345
- call.func.prepare(funcEditor.funcParams).call(true);
376
+ return call.func.prepare(funcEditor.funcParams).call(true);
346
377
  })
347
378
  .show();
348
379
  }
@@ -364,8 +395,7 @@ export async function sequenceSpaceTopMenu(
364
395
  // Delay is required for initial function dialog to close before starting invalidating of molfiles.
365
396
  // Otherwise, dialog is freezing
366
397
  await delay(10);
367
- if (!checkInputColumnUI(macroMolecule, 'Sequence space'))
368
- return;
398
+ if (!checkInputColumnUI(macroMolecule, 'Sequence space')) return;
369
399
 
370
400
  const embedColsNames = getEmbeddingColsNames(table);
371
401
  const withoutEmptyValues = DG.DataFrame.fromColumns([macroMolecule]).clone();
@@ -586,6 +616,7 @@ export function convertDialog() {
586
616
  //name: monomerCellRenderer
587
617
  //tags: cellRenderer
588
618
  //meta.cellType: Monomer
619
+ //meta.columnTags: quality=Monomer
589
620
  //output: grid_cell_renderer result
590
621
  export function monomerCellRenderer(): MonomerCellRenderer {
591
622
  return new MonomerCellRenderer();
@@ -642,20 +673,27 @@ export async function testDetectMacromolecule(path: string): Promise<DG.DataFram
642
673
  return resDf;
643
674
  }
644
675
 
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();
676
+ //name: SplitToMonomersEditor
677
+ //tags: editor
678
+ //input: funccall call
679
+ export function SplitToMonomersEditor(call: DG.FuncCall): void {
680
+ const funcEditor = new SplitToMonomersFunctionEditor();
681
+ ui.dialog({title: 'Split to Monomers'})
682
+ .add(funcEditor.paramsUI)
683
+ .onOK(async () => {
684
+ return call.func.prepare(funcEditor.funcParams).call(true);
685
+ })
686
+ .show();
687
+ }
688
+
689
+ //top-menu: Bio | Split to Monomers
690
+ //name: Split to Monomers
691
+ //input: dataframe table
692
+ //input: column sequence { semType: Macromolecule }
693
+ //output: dataframe result
694
+ //editor: Bio:SplitToMonomersEditor
695
+ export async function splitToMonomersTopMenu(table: DG.DataFrame, sequence: DG.Column): Promise<void> {
696
+ await splitToMonomersUI(table, sequence);
659
697
  }
660
698
 
661
699
  //name: Bio: getHelmMonomers
@@ -9,9 +9,6 @@ import {multipleSequenceAlignmentUI} from '../utils/multiple-sequence-alignment-
9
9
  import {awaitContainerStart} from './utils';
10
10
  //import * as grok from 'datagrok-api/grok';
11
11
 
12
- export const _package = new DG.Package();
13
-
14
-
15
12
  category('MSA', async () => {
16
13
  //table = await grok.data.files.openTable('Demo:Files/bio/peptides.csv');
17
14
  const fromCsv = `seq
@@ -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(
@@ -0,0 +1,27 @@
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 enum MonomerWidthMode {
6
+ long = 'long',
7
+ short = 'short',
8
+ }
9
+
10
+ export const enum Tags {
11
+ calculated = '.mm.cellRenderer.calculated',
12
+ }
13
+
14
+ export const enum Temps {
15
+ monomerWidth = '.mm.cellRenderer.monomerWidth',
16
+ maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
17
+ colorCode = '.mm.cellRenderer.colorCode',
18
+ compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
19
+ highlightDifference = '.mm.cellRenderer.highlightDifference',
20
+ }
21
+
22
+ // export const MacromoleculeCellRendererDefaults = new class {
23
+ // monomerWidth: MonomerWidthMode = MonomerWidthMode.short;
24
+ // maxMonomerLength: number = 3;
25
+ // colorCode: boolean = true;
26
+ // compareWithCurrent: boolean = true;
27
+ // }();
@@ -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,11 @@ 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
+ import {Tags as mmcrTags, Temps as mmcrTemps} from '../utils/cell-renderer-consts';
19
+
20
+ import * as C from './constants';
21
+ import {_package} from '../package';
18
22
 
19
23
  const enum tempTAGS {
20
24
  referenceSequence = 'reference-sequence',
@@ -151,19 +155,19 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
151
155
  const referenceSequence: string[] = splitterFunc(
152
156
  ((tempReferenceSequence != null) && (tempReferenceSequence != '')) ?
153
157
  tempReferenceSequence : tempCurrentWord ?? '');
154
- const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
158
+ const monomerWidth: string = tempMonomerWidth ?? 'short';
155
159
 
156
160
  let gapRenderer = 5;
157
161
  let maxIndex = 0;
158
- let maxLengthOfMonomer = 8;
162
+ let maxLengthOfMonomer: number = 8;
159
163
 
160
164
  if (monomerWidth === 'short') {
161
165
  gapRenderer = 12;
162
- maxLengthOfMonomer = 1;
166
+ maxLengthOfMonomer = colTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.maxMonomerLength;
163
167
  }
164
168
 
165
169
  let maxLengthWords: any = {};
166
- if (gridCell.cell.column.getTag('.calculatedCellRender') !== splitLimit.toString()) {
170
+ if (gridCell.cell.column.getTag(mmcrTags.calculated) !== splitLimit.toString()) {
167
171
  let samples = 0;
168
172
  while (samples < Math.min(gridCell.cell.column.length, 100)) {
169
173
  const column = gridCell.cell.column.get(samples);
@@ -185,7 +189,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
185
189
  colTemp[tempTAGS.bioSumMaxLengthWords] = maxLengthWordSum;
186
190
  colTemp[tempTAGS.bioMaxIndex] = maxIndex;
187
191
  colTemp[tempTAGS.bioMaxLengthWords] = maxLengthWords;
188
- gridCell.cell.column.setTag('.calculatedCellRender', splitLimit.toString());
192
+ gridCell.cell.column.setTag(mmcrTags.calculated, splitLimit.toString());
189
193
  }
190
194
  } else {
191
195
  maxLengthWords = colTemp[tempTAGS.bioMaxLengthWords];
@@ -215,58 +219,6 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
215
219
  }
216
220
  }
217
221
 
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
222
 
271
223
  export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
272
224
  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
+ }
@@ -0,0 +1,28 @@
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
+ import {_package} from '../package';
5
+
6
+ export class PackageSettingsEditorWidget extends DG.Widget {
7
+ maxMonomerLengthProp: DG.Property;
8
+
9
+ constructor(propList: DG.Property[]) {
10
+ super(ui.div([], {}));
11
+
12
+ const props: { [name: string]: DG.Property } =
13
+ Object.assign({}, ...propList.map((p) => ({[p.name]: p})));
14
+
15
+ this.maxMonomerLengthProp = props['MaxMonomerLength'];
16
+ }
17
+
18
+ async init(): Promise<void> {
19
+ const maxMonomerLengthInput = ui.intInput('Max monomer length',
20
+ _package.properties.maxMonomerLength,
21
+ (value: number) => {
22
+ // Handle user changed value
23
+ _package.properties.maxMonomerLength = value;
24
+ });
25
+
26
+ this.root.appendChild(ui.form([maxMonomerLengthInput,]));
27
+ }
28
+ }