@datagrok/bio 2.7.2 → 2.8.1
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 +46 -0
- package/detectors.js +30 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +9 -3
- package/src/package-types.ts +19 -8
- package/src/package.ts +17 -4
- package/src/tests/converters-test.ts +3 -3
- package/src/utils/cell-renderer.ts +1 -1
- package/src/utils/context-menu.ts +30 -0
- package/src/utils/convert.ts +2 -4
- package/src/utils/macromolecule-column-widget.ts +1 -1
- package/src/utils/monomer-cell-renderer.ts +2 -2
- package/src/viewers/vd-regions-viewer.ts +2 -1
- package/src/widgets/package-settings-editor-widget.ts +16 -6
- package/src/widgets/representations.ts +1 -1
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.
|
|
8
|
+
"version": "2.8.1",
|
|
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",
|
|
@@ -24,14 +24,20 @@
|
|
|
24
24
|
"propertyType": "bool",
|
|
25
25
|
"defaultValue": "true",
|
|
26
26
|
"nullable": false
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "DefaultSeparator",
|
|
30
|
+
"propertyType": "string",
|
|
31
|
+
"defaultValue": ".",
|
|
32
|
+
"nullable": false
|
|
27
33
|
}
|
|
28
34
|
],
|
|
29
35
|
"dependencies": {
|
|
30
36
|
"@biowasm/aioli": "^3.1.0",
|
|
31
|
-
"@datagrok-libraries/bio": "^5.
|
|
37
|
+
"@datagrok-libraries/bio": "^5.34.0",
|
|
32
38
|
"@datagrok-libraries/chem-meta": "^1.0.1",
|
|
33
39
|
"@datagrok-libraries/ml": "^6.3.39",
|
|
34
|
-
"@datagrok-libraries/tutorials": "^1.3.
|
|
40
|
+
"@datagrok-libraries/tutorials": "^1.3.6",
|
|
35
41
|
"@datagrok-libraries/utils": "^4.0.17",
|
|
36
42
|
"cash-dom": "^8.0.0",
|
|
37
43
|
"css-loader": "^6.7.3",
|
package/src/package-types.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {ObjectPropertyBag} from 'datagrok-api/dg';
|
|
|
9
9
|
export const enum BioPackagePropertiesNames {
|
|
10
10
|
MaxMonomerLength = 'MaxMonomerLength',
|
|
11
11
|
TooltipWebLogo = 'TooltipWebLogo',
|
|
12
|
+
DefaultSeparator = 'DefaultSeparator',
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
|
|
@@ -18,24 +19,34 @@ export class BioPackageProperties extends Map<string, any> {
|
|
|
18
19
|
public get onPropertyChanged(): Observable<string> { return this._onPropertyChanged; }
|
|
19
20
|
|
|
20
21
|
/** Monomer name maximum length displayed in short mode. */
|
|
21
|
-
public get
|
|
22
|
-
return super.get(BioPackagePropertiesNames.MaxMonomerLength) as
|
|
22
|
+
public get MaxMonomerLength(): number {
|
|
23
|
+
return super.get(BioPackagePropertiesNames.MaxMonomerLength) as number;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
public set
|
|
26
|
-
super.set(BioPackagePropertiesNames.MaxMonomerLength, value
|
|
26
|
+
public set MaxMonomerLength(value: number) {
|
|
27
|
+
super.set(BioPackagePropertiesNames.MaxMonomerLength, value);
|
|
27
28
|
this._onPropertyChanged.next(BioPackagePropertiesNames.MaxMonomerLength);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
public get
|
|
31
|
-
return super.get(BioPackagePropertiesNames.TooltipWebLogo) as
|
|
31
|
+
public get TooltipWebLogo(): boolean {
|
|
32
|
+
return super.get(BioPackagePropertiesNames.TooltipWebLogo) as boolean;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
public set
|
|
35
|
-
super.set(BioPackagePropertiesNames.TooltipWebLogo, value
|
|
35
|
+
public set TooltipWebLogo(value: boolean) {
|
|
36
|
+
super.set(BioPackagePropertiesNames.TooltipWebLogo, value);
|
|
36
37
|
this._onPropertyChanged.next(BioPackagePropertiesNames.TooltipWebLogo);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
public get DefaultSeparator(): string {
|
|
41
|
+
return super.get(BioPackagePropertiesNames.DefaultSeparator) as string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public set DefaultSeparator(value: string) {
|
|
45
|
+
if (value.length !== 1) throw new Error('The separator must be of length one.');
|
|
46
|
+
super.set(BioPackagePropertiesNames.DefaultSeparator, value);
|
|
47
|
+
this._onPropertyChanged.next(BioPackagePropertiesNames.DefaultSeparator);
|
|
48
|
+
}
|
|
49
|
+
|
|
39
50
|
constructor(source: any) {
|
|
40
51
|
super(Object.entries(source));
|
|
41
52
|
}
|
package/src/package.ts
CHANGED
|
@@ -64,6 +64,7 @@ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
|
64
64
|
import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
|
|
65
65
|
import {getCompositionAnalysisWidget} from './widgets/composition-analysis-widget';
|
|
66
66
|
import {MacromoleculeColumnWidget} from './utils/macromolecule-column-widget';
|
|
67
|
+
import {addCopyMenuUI} from './utils/context-menu';
|
|
67
68
|
|
|
68
69
|
export const _package = new BioPackage();
|
|
69
70
|
|
|
@@ -264,7 +265,7 @@ export function SeqActivityCliffsEditor(call: DG.FuncCall) {
|
|
|
264
265
|
|
|
265
266
|
//top-menu: Bio | Analyze | Activity Cliffs...
|
|
266
267
|
//name: Sequence Activity Cliffs
|
|
267
|
-
//description:
|
|
268
|
+
//description: Detects pairs of molecules with similar structure and significant difference in any given property
|
|
268
269
|
//input: dataframe table [Input data table]
|
|
269
270
|
//input: column molecules {semType: Macromolecule}
|
|
270
271
|
//input: column activities
|
|
@@ -358,6 +359,7 @@ export function SequenceSpaceEditor(call: DG.FuncCall) {
|
|
|
358
359
|
|
|
359
360
|
//top-menu: Bio | Analyze | Sequence Space...
|
|
360
361
|
//name: Sequence Space
|
|
362
|
+
//description: Creates 2D sequence space with projected sequences by pairwise distance
|
|
361
363
|
//input: dataframe table
|
|
362
364
|
//input: column molecules { semType: Macromolecule }
|
|
363
365
|
//input: string methodName { choices:["UMAP", "t-SNE"] }
|
|
@@ -456,7 +458,7 @@ export async function sequenceSpaceTopMenu(
|
|
|
456
458
|
|
|
457
459
|
//top-menu: Bio | Convert | To Atomic Level...
|
|
458
460
|
//name: To Atomic Level
|
|
459
|
-
//description:
|
|
461
|
+
//description: Converts sequences to molblocks
|
|
460
462
|
//input: dataframe df [Input data table]
|
|
461
463
|
//input: column macroMolecule {semType: Macromolecule}
|
|
462
464
|
export async function toAtomicLevel(df: DG.DataFrame, macroMolecule: DG.Column): Promise<void> {
|
|
@@ -479,6 +481,7 @@ export async function toAtomicLevel(df: DG.DataFrame, macroMolecule: DG.Column):
|
|
|
479
481
|
|
|
480
482
|
//top-menu: Bio | Analyze | MSA...
|
|
481
483
|
//name: MSA
|
|
484
|
+
//description: Performs multiple sequence alignment
|
|
482
485
|
//tags: bio, panel
|
|
483
486
|
export function multipleSequenceAlignmentDialog(): void {
|
|
484
487
|
multipleSequenceAlignmentUI();
|
|
@@ -497,6 +500,7 @@ export async function alignSequences(sequenceCol: DG.Column<string> | null = nul
|
|
|
497
500
|
|
|
498
501
|
//top-menu: Bio | Analyze | Composition
|
|
499
502
|
//name: Composition Analysis
|
|
503
|
+
//description: Visualizes sequence composition on a WebLogo plot
|
|
500
504
|
//meta.icon: files/icons/composition-analysis.svg
|
|
501
505
|
//output: viewer result
|
|
502
506
|
export async function compositionAnalysis(): Promise<void> {
|
|
@@ -704,7 +708,7 @@ export function similaritySearchViewer(): SequenceSimilarityViewer {
|
|
|
704
708
|
|
|
705
709
|
//top-menu: Bio | Search | Similarity
|
|
706
710
|
//name: similaritySearch
|
|
707
|
-
//description:
|
|
711
|
+
//description: Finds similar sequences
|
|
708
712
|
//output: viewer result
|
|
709
713
|
export function similaritySearchTopMenu(): void {
|
|
710
714
|
const view = (grok.shell.v as DG.TableView);
|
|
@@ -722,7 +726,7 @@ export function diversitySearchViewer(): SequenceDiversityViewer {
|
|
|
722
726
|
|
|
723
727
|
//top-menu: Bio | Search | Diversity
|
|
724
728
|
//name: diversitySearch
|
|
725
|
-
//description:
|
|
729
|
+
//description: Finds the most diverse sequences
|
|
726
730
|
//output: viewer result
|
|
727
731
|
export function diversitySearchTopMenu() {
|
|
728
732
|
const view = (grok.shell.v as DG.TableView);
|
|
@@ -732,6 +736,7 @@ export function diversitySearchTopMenu() {
|
|
|
732
736
|
|
|
733
737
|
//top-menu: Bio | Search | Substructure...
|
|
734
738
|
//name: bioSubstructureSearch
|
|
739
|
+
//description: Finds sequence with the given subsequence
|
|
735
740
|
export function bioSubstructureSearch(): void {
|
|
736
741
|
const col = getMacromoleculeColumn();
|
|
737
742
|
substructureSearchDialog(col);
|
|
@@ -768,6 +773,14 @@ export async function webLogoLargeApp(): Promise<void> {
|
|
|
768
773
|
}
|
|
769
774
|
}
|
|
770
775
|
|
|
776
|
+
// -- Handle context menu --
|
|
777
|
+
|
|
778
|
+
///name: addCopyMenu
|
|
779
|
+
//input: object cell
|
|
780
|
+
//input: object menu
|
|
781
|
+
export function addCopyMenu(cell: DG.Cell, menu: DG.Menu): void {
|
|
782
|
+
addCopyMenuUI(cell, menu);
|
|
783
|
+
}
|
|
771
784
|
|
|
772
785
|
// -- Demo --
|
|
773
786
|
|
|
@@ -129,7 +129,7 @@ RNA1{P.R(U)P.R(U)P.R(C)P.R(A)P.R(A)P.R(C)P.P.P}$$$$`,
|
|
|
129
129
|
return df;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
function converter(tgtNotation: NOTATION, tgtSeparator
|
|
132
|
+
function converter(tgtNotation: NOTATION, tgtSeparator?: string): ConverterFunc {
|
|
133
133
|
if (tgtNotation === NOTATION.SEPARATOR && !tgtSeparator)
|
|
134
134
|
throw new Error(`Argument 'separator' is mandatory for target notation '${tgtNotation.toString()}'.`);
|
|
135
135
|
|
|
@@ -141,12 +141,12 @@ RNA1{P.R(U)P.R(U)P.R(C)P.R(A)P.R(A)P.R(C)P.P.P}$$$$`,
|
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
async function _testConvert(srcKey: Samples,
|
|
144
|
+
async function _testConvert(srcKey: Samples, colConverter: ConverterFunc, tgtKey: Samples) {
|
|
145
145
|
const srcDf: DG.DataFrame = await readCsv(srcKey);
|
|
146
146
|
const srcCol: DG.Column = srcDf.getCol('seq');
|
|
147
147
|
|
|
148
148
|
// conversion results
|
|
149
|
-
const resCol: DG.Column =
|
|
149
|
+
const resCol: DG.Column = colConverter(srcCol);
|
|
150
150
|
|
|
151
151
|
// The correct reference data to compare conversion results with.
|
|
152
152
|
const tgtDf: DG.DataFrame = await readCsv(tgtKey);
|
|
@@ -135,7 +135,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
135
135
|
const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
|
|
136
136
|
const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
|
|
137
137
|
if (monomerWidth === 'short')
|
|
138
|
-
maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.
|
|
138
|
+
maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.MaxMonomerLength;
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
let seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
|
|
@@ -0,0 +1,30 @@
|
|
|
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 {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
6
|
+
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
+
import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
8
|
+
|
|
9
|
+
import {_package} from '../package';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export function addCopyMenuUI(cell: DG.Cell, menu: DG.Menu): void {
|
|
13
|
+
const uh = UnitsHandler.getOrCreate(cell.column);
|
|
14
|
+
const tgtNotationList: string[] = Object.values(NOTATION).filter((v) => v !== uh.units);
|
|
15
|
+
|
|
16
|
+
menu.group('Copy')
|
|
17
|
+
.items(tgtNotationList, (tgtNotation) => {
|
|
18
|
+
const nc = new NotationConverter(cell.column);
|
|
19
|
+
const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.DefaultSeparator : undefined;
|
|
20
|
+
const converter = nc.getConverter(tgtNotation as NOTATION, separator);
|
|
21
|
+
const tgtSeq = converter(cell.value);
|
|
22
|
+
|
|
23
|
+
if (!navigator.clipboard) {
|
|
24
|
+
grok.shell.warning('The clipboard functionality requires a secure origin — either HTTPS or localhost');
|
|
25
|
+
} else {
|
|
26
|
+
navigator.clipboard.writeText(tgtSeq);
|
|
27
|
+
grok.shell.info(`Value of notation '${tgtNotation}' copied to clipboard`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
package/src/utils/convert.ts
CHANGED
|
@@ -97,7 +97,7 @@ export function convert(col?: DG.Column): void {
|
|
|
97
97
|
]))
|
|
98
98
|
.onOK(async () => {
|
|
99
99
|
const targetNotation = targetNotationInput.value as NOTATION;
|
|
100
|
-
const separator: string |
|
|
100
|
+
const separator: string | undefined = separatorInput.value ?? undefined;
|
|
101
101
|
|
|
102
102
|
await convertDo(tgtCol, targetNotation, separator);
|
|
103
103
|
})
|
|
@@ -116,9 +116,7 @@ export function convert(col?: DG.Column): void {
|
|
|
116
116
|
* @param {NOTATION} targetNotation Target notation
|
|
117
117
|
* @param {string | null} separator Separator for SEPARATOR notation
|
|
118
118
|
*/
|
|
119
|
-
export async function convertDo(
|
|
120
|
-
srcCol: DG.Column, targetNotation: NOTATION, separator: string | null,
|
|
121
|
-
): Promise<DG.Column> {
|
|
119
|
+
export async function convertDo(srcCol: DG.Column, targetNotation: NOTATION, separator?: string): Promise<DG.Column> {
|
|
122
120
|
const converter = new NotationConverter(srcCol);
|
|
123
121
|
const newColumn = converter.convert(targetNotation, separator);
|
|
124
122
|
srcCol.dataFrame.columns.add(newColumn);
|
|
@@ -24,7 +24,7 @@ export class MacromoleculeColumnWidget extends DG.Widget {
|
|
|
24
24
|
|
|
25
25
|
async init(): Promise<void> {
|
|
26
26
|
const uh = UnitsHandler.getOrCreate(this.seqCol);
|
|
27
|
-
const pkgTooltipWebLogo = _package.properties.
|
|
27
|
+
const pkgTooltipWebLogo = _package.properties.TooltipWebLogo;
|
|
28
28
|
const colTooltipWebLogo = this.seqCol.getTag(wlTAGS.tooltipWebLogo);
|
|
29
29
|
|
|
30
30
|
if (pkgTooltipWebLogo !== false && !['false', 'off', 'disable', 'disabled'].includes(colTooltipWebLogo)) {
|
|
@@ -63,7 +63,7 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
|
|
|
63
63
|
|
|
64
64
|
get defaultHeight(): number { return 15; }
|
|
65
65
|
|
|
66
|
-
get defaultWidth(): number { return
|
|
66
|
+
get defaultWidth(): number { return 40; }
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Cell renderer function.
|
|
@@ -95,6 +95,6 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
|
|
|
95
95
|
const color = palette.get(s);
|
|
96
96
|
|
|
97
97
|
g.fillStyle = color;
|
|
98
|
-
g.fillText(monomerToShort(s,
|
|
98
|
+
g.fillText(monomerToShort(s, 6), x + (w / 2), y + (h / 2), w);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -316,7 +316,8 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
316
316
|
this.filterSourceInput.root.style.position = 'absolute';
|
|
317
317
|
this.filterSourceInput.root.style.left = '10px';
|
|
318
318
|
this.filterSourceInput.root.style.top = '-3px';
|
|
319
|
-
|
|
319
|
+
//this.filterSourceInput.setTooltip('Check to filter sequences for selected VRs'); // TODO: GROK-13614
|
|
320
|
+
ui.tooltip.bind(this.filterSourceInput.input, 'Check to filter sequences for selected VRs');
|
|
320
321
|
|
|
321
322
|
const _color: string = `#ffbb${Math.ceil(Math.random() * 255).toString(16)}`;
|
|
322
323
|
this.host = ui.div([this.mainLayout, this.filterSourceInput!.root],
|
|
@@ -6,6 +6,7 @@ import {_package} from '../package';
|
|
|
6
6
|
export class PackageSettingsEditorWidget extends DG.Widget {
|
|
7
7
|
maxMonomerLengthProp: DG.Property;
|
|
8
8
|
tooltipWebLogo: DG.Property;
|
|
9
|
+
defaultSeparator: DG.Property;
|
|
9
10
|
|
|
10
11
|
constructor(propList: DG.Property[]) {
|
|
11
12
|
super(ui.div([], {}));
|
|
@@ -15,24 +16,33 @@ export class PackageSettingsEditorWidget extends DG.Widget {
|
|
|
15
16
|
|
|
16
17
|
this.maxMonomerLengthProp = props['MaxMonomerLength'];
|
|
17
18
|
this.tooltipWebLogo = props['TooltipWebLogo'];
|
|
19
|
+
this.defaultSeparator = props['DefaultSeparator'];
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
async init(): Promise<void> {
|
|
21
23
|
const maxMonomerLengthInput = ui.intInput('Max monomer length',
|
|
22
|
-
_package.properties.
|
|
24
|
+
_package.properties.MaxMonomerLength,
|
|
23
25
|
(value: number) => {
|
|
24
26
|
// Handle user changed value
|
|
25
|
-
_package.properties.
|
|
27
|
+
_package.properties.MaxMonomerLength = value;
|
|
26
28
|
});
|
|
27
29
|
|
|
28
|
-
const
|
|
29
|
-
_package.properties.
|
|
30
|
+
const tooltipWebLogoInput = ui.boolInput('Tooltip WebLogo',
|
|
31
|
+
_package.properties.TooltipWebLogo,
|
|
30
32
|
(value: boolean) => {
|
|
31
|
-
_package.properties.
|
|
33
|
+
_package.properties.TooltipWebLogo = value;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const defaultSeparatorInput = ui.choiceInput('Default Separator',
|
|
37
|
+
_package.properties.DefaultSeparator, ['.', '/', '-'],
|
|
38
|
+
(value: string) => {
|
|
39
|
+
_package.properties.DefaultSeparator = value;
|
|
32
40
|
});
|
|
33
41
|
|
|
34
42
|
this.root.appendChild(ui.form([
|
|
35
43
|
maxMonomerLengthInput,
|
|
36
|
-
|
|
44
|
+
tooltipWebLogoInput,
|
|
45
|
+
defaultSeparatorInput,
|
|
46
|
+
]));
|
|
37
47
|
}
|
|
38
48
|
}
|
|
@@ -32,7 +32,7 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
|
|
|
32
32
|
);
|
|
33
33
|
|
|
34
34
|
const maxMonomerLength: DG.InputBase = ui.intInput('Max monomer length',
|
|
35
|
-
col.temp[mmcrTemps.maxMonomerLength] ?? _package.properties.
|
|
35
|
+
col.temp[mmcrTemps.maxMonomerLength] ?? _package.properties.MaxMonomerLength,
|
|
36
36
|
(value: number) => {
|
|
37
37
|
col.temp[mmcrTemps.maxMonomerLength] = value;
|
|
38
38
|
col.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.true);
|