@datagrok/bio 2.27.0 → 2.27.2
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/dist/287.js +1 -1
- package/dist/287.js.map +1 -1
- package/dist/422.js +1 -1
- package/dist/package-test.js +2 -2
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/package.json +3 -3
- package/scripts/mol-to-helm.py +642 -170
- package/src/analysis/sequence-activity-cliffs.ts +8 -6
- package/src/package-api.ts +2 -2
- package/src/package.g.ts +7 -0
- package/src/package.ts +12 -1
- package/src/utils/annotations/annotation-manager-ui.ts +1 -1
- package/src/utils/compare-sequences.ts +104 -0
- package/src/utils/monomer-lib/library-file-manager/ui.ts +1 -1
- package/src/utils/monomer-lib/monomer-manager/monomer-manager.ts +1 -1
- package/src/utils/multiple-sequence-alignment-ui.ts +2 -2
- package/test-console-output-1.log +518 -532
- package/test-record-1.mp4 +0 -0
|
@@ -181,12 +181,14 @@ export function createDifferencesWithPositions(
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export function createLinesGrid(df: DG.DataFrame, colNames: string[]): DG.Grid {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
if (!df.col('seq_diff')) {
|
|
185
|
+
const seqDiffCol = DG.Column.string('seq_diff', df.rowCount)
|
|
186
|
+
.init((i) => `${df.get(colNames[0], i)}#${df.get(colNames[1], i)}`);
|
|
187
|
+
seqDiffCol.semType = 'MacromoleculeDifference';
|
|
188
|
+
seqDiffCol.meta.units = df.col(colNames[0])!.meta.units;
|
|
189
|
+
seqDiffCol.setTag(bioTAGS.separator, df.col(colNames[0])!.getTag(bioTAGS.separator));
|
|
190
|
+
df.columns.add(seqDiffCol);
|
|
191
|
+
}
|
|
190
192
|
const grid = df.plot.grid();
|
|
191
193
|
grid.col(colNames[0])!.visible = false;
|
|
192
194
|
grid.col(colNames[1])!.visible = false;
|
package/src/package-api.ts
CHANGED
|
@@ -15,8 +15,8 @@ export namespace scripts {
|
|
|
15
15
|
/**
|
|
16
16
|
Converts molecules to HELM notation based on monomer library
|
|
17
17
|
*/
|
|
18
|
-
export async function molToHelmConverterPy(moleculesDataframe: DG.DataFrame , moleculesColumn: DG.Column ,
|
|
19
|
-
return await grok.functions.call('Bio:MolToHelmConverterPy', { moleculesDataframe, moleculesColumn,
|
|
18
|
+
export async function molToHelmConverterPy(moleculesDataframe: DG.DataFrame , moleculesColumn: DG.Column , libraryFile: DG.FileInfo ): Promise<DG.DataFrame> {
|
|
19
|
+
return await grok.functions.call('Bio:MolToHelmConverterPy', { moleculesDataframe, moleculesColumn, libraryFile });
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
package/src/package.g.ts
CHANGED
|
@@ -456,6 +456,13 @@ export async function pepseaMsa(sequenceCol: DG.Column<any>, method: string, gap
|
|
|
456
456
|
return await PackageFunctions.pepseaMsa(sequenceCol, method, gapOpen, gapExtend);
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
+
//name: Compare Sequences
|
|
460
|
+
//description: Builds a MacromoleculeDifference column from two sequence columns (seq1#seq2)
|
|
461
|
+
//top-menu: Bio | Analyze | Compare sequences...
|
|
462
|
+
export function compareSequences() : void {
|
|
463
|
+
PackageFunctions.compareSequences();
|
|
464
|
+
}
|
|
465
|
+
|
|
459
466
|
//name: Composition Analysis
|
|
460
467
|
//description: Visualizes sequence composition on a WebLogo plot
|
|
461
468
|
//output: viewer result
|
package/src/package.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {SequenceSimilarityViewer} from './analysis/sequence-similarity-viewer';
|
|
|
44
44
|
import {SequenceDiversityViewer} from './analysis/sequence-diversity-viewer';
|
|
45
45
|
import {invalidateMols, MONOMERIC_COL_TAGS, SubstructureSearchDialog} from './substructure-search/substructure-search';
|
|
46
46
|
import {convert} from './utils/convert';
|
|
47
|
+
import {compareSequencesUI} from './utils/compare-sequences';
|
|
47
48
|
import {getMacromoleculeColumnPropertyPanel} from './widgets/representations';
|
|
48
49
|
import {getMonomerInfoWidget} from './widgets/monomer-info-widget';
|
|
49
50
|
import {saveAsFastaUI} from './utils/save-as-fasta';
|
|
@@ -810,7 +811,8 @@ export class PackageFunctions {
|
|
|
810
811
|
// collect current monomer library
|
|
811
812
|
const monomerLib = _package.monomerLib;
|
|
812
813
|
const libJSON = JSON.stringify(monomerLib.toJSON());
|
|
813
|
-
|
|
814
|
+
const fileInfo = DG.FileInfo.fromString('monomerLib.json', libJSON);
|
|
815
|
+
await api.scripts.molToHelmConverterPy(table, molecules, fileInfo);
|
|
814
816
|
|
|
815
817
|
// semtype is not automatically set, so we set it manually
|
|
816
818
|
const newCol = table.columns.toList().find((c) => c.name.toLowerCase().includes('regenerated sequence') && c.semType !== DG.SEMTYPE.MACROMOLECULE);
|
|
@@ -991,6 +993,15 @@ export class PackageFunctions {
|
|
|
991
993
|
return alignWithPepsea(sequenceCol, method, gapOpen, gapExtend);
|
|
992
994
|
}
|
|
993
995
|
|
|
996
|
+
@grok.decorators.func({
|
|
997
|
+
name: 'Compare Sequences',
|
|
998
|
+
description: 'Builds a MacromoleculeDifference column from two sequence columns (seq1#seq2)',
|
|
999
|
+
'top-menu': 'Bio | Analyze | Compare sequences...',
|
|
1000
|
+
})
|
|
1001
|
+
static compareSequences(): void {
|
|
1002
|
+
compareSequencesUI();
|
|
1003
|
+
}
|
|
1004
|
+
|
|
994
1005
|
@grok.decorators.func({
|
|
995
1006
|
name: 'Composition Analysis',
|
|
996
1007
|
description: 'Visualizes sequence composition on a WebLogo plot',
|
|
@@ -63,7 +63,7 @@ export function showAnnotationManagerDialog(): void {
|
|
|
63
63
|
setColumnAnnotations(selectedCol, updated);
|
|
64
64
|
df.fireValuesChanged();
|
|
65
65
|
refreshList();
|
|
66
|
-
});
|
|
66
|
+
}, 'Delete');
|
|
67
67
|
removeBtn.style.cursor = 'pointer';
|
|
68
68
|
removeBtn.style.color = '#999';
|
|
69
69
|
removeBtn.style.marginLeft = '8px';
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
|
+
import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
|
|
7
|
+
|
|
8
|
+
import * as C from './constants';
|
|
9
|
+
import {getMacromoleculeColumns} from './ui-utils';
|
|
10
|
+
|
|
11
|
+
/** Builds a `MacromoleculeDifference` column from two sequence columns by encoding each row as
|
|
12
|
+
* `seq1#seq2`. The result copies the relevant metadata (notation, separator, notation provider)
|
|
13
|
+
* from `seqCol1` — callers are responsible for ensuring the two input columns are compatible. */
|
|
14
|
+
export function compareSequencesDo(
|
|
15
|
+
seqCol1: DG.Column<string>, seqCol2: DG.Column<string>, resultName?: string,
|
|
16
|
+
): DG.Column<string> {
|
|
17
|
+
const rowCount = Math.min(seqCol1.length, seqCol2.length);
|
|
18
|
+
const values: string[] = new Array(rowCount);
|
|
19
|
+
for (let i = 0; i < rowCount; i++) {
|
|
20
|
+
const v1 = seqCol1.get(i) ?? '';
|
|
21
|
+
const v2 = seqCol2.get(i) ?? '';
|
|
22
|
+
values[i] = `${v1}#${v2}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const name = resultName ?? `${seqCol1.name} vs ${seqCol2.name}`;
|
|
26
|
+
const diffCol = DG.Column.fromStrings(name, values);
|
|
27
|
+
diffCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
28
|
+
|
|
29
|
+
const sep = seqCol1.getTag(bioTAGS.separator);
|
|
30
|
+
if (sep != null) diffCol.tags[bioTAGS.separator] = sep;
|
|
31
|
+
const units = seqCol1.getTag(DG.TAGS.UNITS);
|
|
32
|
+
if (units != null) diffCol.tags[DG.TAGS.UNITS] = units;
|
|
33
|
+
const aligned = seqCol1.getTag(bioTAGS.aligned);
|
|
34
|
+
if (aligned != null) diffCol.tags[bioTAGS.aligned] = aligned;
|
|
35
|
+
const alphabet = seqCol1.getTag(bioTAGS.alphabet);
|
|
36
|
+
if (alphabet != null) diffCol.tags[bioTAGS.alphabet] = alphabet;
|
|
37
|
+
|
|
38
|
+
diffCol.tags[DG.TAGS.CELL_RENDERER] = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
39
|
+
diffCol.temp[SeqTemps.notationProvider] = seqCol1.temp[SeqTemps.notationProvider];
|
|
40
|
+
|
|
41
|
+
return diffCol;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Validates that two macromolecule columns are compatible for pair-wise difference rendering:
|
|
45
|
+
* identical notation/alignment/alphabet and (for separator notation) matching separator. */
|
|
46
|
+
function checkColumnsCompatible(c1: DG.Column, c2: DG.Column): string | null {
|
|
47
|
+
if (c1 === c2) return 'Please choose two distinct columns';
|
|
48
|
+
if (c1.semType !== DG.SEMTYPE.MACROMOLECULE || c2.semType !== DG.SEMTYPE.MACROMOLECULE)
|
|
49
|
+
return 'Both columns must be Macromolecule semantic type';
|
|
50
|
+
if (c1.getTag(DG.TAGS.UNITS) !== c2.getTag(DG.TAGS.UNITS))
|
|
51
|
+
return 'Columns must use the same notation (units)';
|
|
52
|
+
if ((c1.getTag(bioTAGS.separator) ?? '') !== (c2.getTag(bioTAGS.separator) ?? ''))
|
|
53
|
+
return 'Columns must use the same separator';
|
|
54
|
+
if ((c1.getTag(bioTAGS.alphabet) ?? '') !== (c2.getTag(bioTAGS.alphabet) ?? ''))
|
|
55
|
+
return 'Columns must use the same alphabet';
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Top-menu entry point for `Bio | Analyze | Compare sequences`. Opens a simple dialog to pick
|
|
60
|
+
* two Macromolecule columns from the current table and appends a `MacromoleculeDifference`
|
|
61
|
+
* column to the dataframe. */
|
|
62
|
+
export function compareSequencesUI(): void {
|
|
63
|
+
const tv = grok.shell.tv;
|
|
64
|
+
if (!tv || !tv.dataFrame) {
|
|
65
|
+
grok.shell.error('No active table');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const df = tv.dataFrame;
|
|
69
|
+
const cols: DG.Column[] = getMacromoleculeColumns();
|
|
70
|
+
if (cols.length < 2) {
|
|
71
|
+
grok.shell.error('Current table needs at least two Macromolecule columns');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const names = cols.map((c) => c.name);
|
|
76
|
+
const col1Input = ui.input.choice('Sequence column 1', {value: names[0], items: names});
|
|
77
|
+
const col2Input = ui.input.choice('Sequence column 2', {value: names[1], items: names});
|
|
78
|
+
const resultNameInput = ui.input.string('Result column name', {value: ''});
|
|
79
|
+
resultNameInput.setTooltip('Leave empty to auto-generate from the chosen columns');
|
|
80
|
+
|
|
81
|
+
ui.dialog({title: 'Compare Sequences'})
|
|
82
|
+
.add(col1Input)
|
|
83
|
+
.add(col2Input)
|
|
84
|
+
.add(resultNameInput)
|
|
85
|
+
.onOK(() => {
|
|
86
|
+
const c1 = df.col(col1Input.value ?? '');
|
|
87
|
+
const c2 = df.col(col2Input.value ?? '');
|
|
88
|
+
if (!c1 || !c2) {
|
|
89
|
+
grok.shell.error('Could not resolve chosen columns');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const err = checkColumnsCompatible(c1, c2);
|
|
93
|
+
if (err != null) {
|
|
94
|
+
grok.shell.error(err);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const desired = (resultNameInput.value ?? '').trim() || `${c1.name} vs ${c2.name}`;
|
|
98
|
+
const name = df.columns.getUnusedName(desired);
|
|
99
|
+
const diffCol = compareSequencesDo(
|
|
100
|
+
c1 as DG.Column<string>, c2 as DG.Column<string>, name);
|
|
101
|
+
df.columns.add(diffCol);
|
|
102
|
+
})
|
|
103
|
+
.show();
|
|
104
|
+
}
|
|
@@ -198,7 +198,7 @@ class LibraryControlsManager {
|
|
|
198
198
|
updateLibrarySelectionStatus(libInput.value, libFileName);
|
|
199
199
|
}});
|
|
200
200
|
ui.tooltip.bind(libInput.root, `Include monomers from ${libFileName}`);
|
|
201
|
-
const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName));
|
|
201
|
+
const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName), 'Delete');
|
|
202
202
|
const editIcon = ui.icons.edit(async () => {
|
|
203
203
|
grok.shell.v = await (await MonomerManager.getInstance()).getViewRoot(libFileName);
|
|
204
204
|
}, 'Edit monomer library');
|
|
@@ -486,7 +486,7 @@ export class MonomerManager implements IMonomerManager {
|
|
|
486
486
|
}
|
|
487
487
|
const monomer = await monomerFromDfRow(this.tv!.dataFrame.rows.get(currentRowIdx));
|
|
488
488
|
await this._newMonomerForm.removeMonomers([monomer], this.libInput.value!);
|
|
489
|
-
});
|
|
489
|
+
}, 'Delete');
|
|
490
490
|
|
|
491
491
|
ui.tooltip.bind(deleteButton, () =>
|
|
492
492
|
`${(this.tv?.dataFrame?.selection?.trueCount ?? 0) > 0 ? 'Delete selected monomers' : 'Delete monomer'}`);
|
|
@@ -93,7 +93,7 @@ export async function multipleSequenceAlignmentUI(
|
|
|
93
93
|
});
|
|
94
94
|
}, 'Adjust alignment parameters such as penalties for opening and extending gaps');
|
|
95
95
|
kalignParamsButton.classList.add('msa-params-button');
|
|
96
|
-
kalignParamsButton.prepend(ui.icons.settings(() => null));
|
|
96
|
+
kalignParamsButton.prepend(ui.icons.settings(() => null, 'Settings'));
|
|
97
97
|
|
|
98
98
|
const kalignElements = [kalignParamsDiv, kalignParamsButton, kalignVersionDiv];
|
|
99
99
|
|
|
@@ -118,7 +118,7 @@ export async function multipleSequenceAlignmentUI(
|
|
|
118
118
|
engineParamsDiv.hidden = !engineParamsDiv.hidden;
|
|
119
119
|
}, 'Adjust engine-specific alignment parameters');
|
|
120
120
|
engineParamsButton.classList.add('msa-params-button');
|
|
121
|
-
engineParamsButton.prepend(ui.icons.settings(() => null));
|
|
121
|
+
engineParamsButton.prepend(ui.icons.settings(() => null, 'Settings'));
|
|
122
122
|
|
|
123
123
|
// "Include HELM" checkbox: shown when column has a notation provider with fromHelm
|
|
124
124
|
const includeHelmInput = ui.input.bool('Include HELM', {value: true});
|