@datagrok/bio 2.11.40 → 2.11.42
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 +14 -0
- package/dist/package-test.js +5 -5
- package/dist/package-test.js.LICENSE.txt +8 -0
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +5 -5
- package/dist/package.js.LICENSE.txt +8 -0
- package/dist/package.js.map +1 -1
- package/package.json +1 -1
- package/src/const.ts +5 -0
- package/src/tests/WebLogo-positions-test.ts +17 -13
- package/src/tests/bio-tests.ts +6 -1
- package/src/utils/helm-to-molfile.ts +30 -6
- package/src/utils/macromolecule-column-widget.ts +5 -2
- package/src/utils/poly-tool/transformation.ts +2 -2
- package/src/utils/poly-tool/ui.ts +3 -1
- package/src/viewers/web-logo-viewer.ts +53 -60
- package/src/widgets/composition-analysis-widget.ts +19 -12
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.11.
|
|
8
|
+
"version": "2.11.42",
|
|
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",
|
package/src/const.ts
ADDED
|
@@ -11,6 +11,10 @@ import {
|
|
|
11
11
|
} from '../viewers/web-logo-viewer';
|
|
12
12
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
13
13
|
|
|
14
|
+
import {GAP_SYMBOL} from '../const';
|
|
15
|
+
|
|
16
|
+
const g: string = GAP_SYMBOL;
|
|
17
|
+
|
|
14
18
|
category('WebLogo-positions', () => {
|
|
15
19
|
const csvDf1 = `seq
|
|
16
20
|
ATC-G-TTGC--
|
|
@@ -36,18 +40,18 @@ ATC-G-TTGC--
|
|
|
36
40
|
const positions: PI[] = wlViewer['positions'];
|
|
37
41
|
|
|
38
42
|
const resAllDf1: PI[] = [
|
|
39
|
-
new PI(0, '1', {'A': new PMI(2),
|
|
43
|
+
new PI(0, '1', {'A': new PMI(2), [g]: new PMI(3)}),
|
|
40
44
|
new PI(1, '2', {'T': new PMI(5)}),
|
|
41
45
|
new PI(2, '3', {'C': new PMI(5)}),
|
|
42
|
-
new PI(3, '4', {
|
|
46
|
+
new PI(3, '4', {[g]: new PMI(5)}),
|
|
43
47
|
new PI(4, '5', {'G': new PMI(5)}),
|
|
44
|
-
new PI(5, '6', {
|
|
48
|
+
new PI(5, '6', {[g]: new PMI(3), 'C': new PMI(2)}),
|
|
45
49
|
new PI(6, '7', {'T': new PMI(5)}),
|
|
46
50
|
new PI(7, '8', {'T': new PMI(5)}),
|
|
47
51
|
new PI(8, '9', {'G': new PMI(5)}),
|
|
48
52
|
new PI(9, '10', {'C': new PMI(5)}),
|
|
49
|
-
new PI(10, '11', {
|
|
50
|
-
new PI(11, '12', {
|
|
53
|
+
new PI(10, '11', {[g]: new PMI(5)}),
|
|
54
|
+
new PI(11, '12', {[g]: new PMI(5)}),
|
|
51
55
|
];
|
|
52
56
|
|
|
53
57
|
expect(positions.length, resAllDf1.length);
|
|
@@ -89,15 +93,15 @@ ATC-G-TTGC--
|
|
|
89
93
|
const positions: PI[] = wlViewer['positions'];
|
|
90
94
|
|
|
91
95
|
const resAllDf1: PI[] = [
|
|
92
|
-
new PI(0, '1', {
|
|
96
|
+
new PI(0, '1', {[g]: new PMI(3)}),
|
|
93
97
|
new PI(1, '2', {'T': new PMI(3)}),
|
|
94
|
-
new PI(2, '3', {
|
|
95
|
-
new PI(3, '4', {
|
|
98
|
+
new PI(2, '3', {[g]: new PMI(3)}),
|
|
99
|
+
new PI(3, '4', {[g]: new PMI(3)}),
|
|
96
100
|
new PI(4, '5', {'C': new PMI(3)}),
|
|
97
|
-
new PI(5, '6', {
|
|
101
|
+
new PI(5, '6', {[g]: new PMI(2), 'C': new PMI(1)}),
|
|
98
102
|
new PI(6, '7', {'G': new PMI(3)}),
|
|
99
103
|
new PI(7, '8', {'T': new PMI(3)}),
|
|
100
|
-
new PI(8, '9', {
|
|
104
|
+
new PI(8, '9', {[g]: new PMI(3)}),
|
|
101
105
|
];
|
|
102
106
|
|
|
103
107
|
expect(positions.length, resAllDf1.length);
|
|
@@ -128,11 +132,11 @@ ATC-G-TTGC--
|
|
|
128
132
|
const resPosList: PI[] = wlViewer['positions'];
|
|
129
133
|
|
|
130
134
|
const tgtPosList: PI[] = [
|
|
131
|
-
new PI(0, '1', {'A': new PMI(2),
|
|
135
|
+
new PI(0, '1', {'A': new PMI(2), [g]: new PMI(3)}),
|
|
132
136
|
new PI(1, '2', {'T': new PMI(5)}),
|
|
133
137
|
new PI(2, '3', {'C': new PMI(5)}),
|
|
134
138
|
new PI(4, '5', {'G': new PMI(5)}),
|
|
135
|
-
new PI(5, '6', {
|
|
139
|
+
new PI(5, '6', {[g]: new PMI(3), 'C': new PMI(2)}),
|
|
136
140
|
new PI(6, '7', {'T': new PMI(5)}),
|
|
137
141
|
new PI(7, '8', {'T': new PMI(5)}),
|
|
138
142
|
new PI(8, '9', {'G': new PMI(5)}),
|
|
@@ -166,7 +170,7 @@ ATC-G-TTGC--
|
|
|
166
170
|
const tgtPosList: PI[] = [
|
|
167
171
|
new PI(2, '3', {'C': new PMI(5)}),
|
|
168
172
|
new PI(4, '5', {'G': new PMI(5)}),
|
|
169
|
-
new PI(5, '6', {
|
|
173
|
+
new PI(5, '6', {[g]: new PMI(3), 'C': new PMI(2)}),
|
|
170
174
|
new PI(6, '7', {'T': new PMI(5)}),
|
|
171
175
|
];
|
|
172
176
|
|
package/src/tests/bio-tests.ts
CHANGED
|
@@ -16,6 +16,11 @@ import {UnknownSeqPalette} from '@datagrok-libraries/bio/src/unknown';
|
|
|
16
16
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
17
17
|
import {getStatsForCol} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
|
|
18
18
|
|
|
19
|
+
import {GAP_SYMBOL} from '../const';
|
|
20
|
+
|
|
21
|
+
/** GAP_SYMBOL */
|
|
22
|
+
const g: string = GAP_SYMBOL;
|
|
23
|
+
|
|
19
24
|
category('bio', () => {
|
|
20
25
|
const csvDfN1: string = `seq
|
|
21
26
|
ACGTCT
|
|
@@ -144,7 +149,7 @@ export async function _testGetAlphabetSimilarity() {
|
|
|
144
149
|
'C': 3015,
|
|
145
150
|
'G': 3015,
|
|
146
151
|
'T': 2048,
|
|
147
|
-
|
|
152
|
+
[g]: 1000,
|
|
148
153
|
};
|
|
149
154
|
const alphabet: Set<string> = new Set(Object.keys(Nucleotides.Names));
|
|
150
155
|
const res = getAlphabetSimilarity(freq, alphabet);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
|
-
import * as ui from 'datagrok-api/ui';
|
|
4
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
+
import * as OCL from 'openchemlib/full';
|
|
5
5
|
|
|
6
6
|
import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
|
|
7
7
|
import {MolfileHandlerBase} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler-base';
|
|
8
|
-
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
8
|
+
import {RDModule, RDMol} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
9
9
|
import {HELM_POLYMER_TYPE, HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
|
|
10
10
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
11
11
|
|
|
@@ -51,10 +51,10 @@ export async function helm2mol(df: DG.DataFrame, helmCol: DG.Column<string>): Pr
|
|
|
51
51
|
|
|
52
52
|
/** Translate HELM column into molfile column and append to the dataframe */
|
|
53
53
|
export async function getMolColumnFromHelm(
|
|
54
|
-
df: DG.DataFrame, helmCol: DG.Column<string
|
|
54
|
+
df: DG.DataFrame, helmCol: DG.Column<string>, chiralityEngine?: boolean
|
|
55
55
|
): Promise<DG.Column<string>> {
|
|
56
56
|
const converter = new HelmToMolfileConverter(helmCol, df);
|
|
57
|
-
const molCol = await converter.convertToRdKitBeautifiedMolfileColumn();
|
|
57
|
+
const molCol = await converter.convertToRdKitBeautifiedMolfileColumn(chiralityEngine);
|
|
58
58
|
molCol.semType = DG.SEMTYPE.MOLECULE;
|
|
59
59
|
return molCol;
|
|
60
60
|
}
|
|
@@ -89,7 +89,28 @@ export class HelmToMolfileConverter {
|
|
|
89
89
|
return smiles;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
async
|
|
92
|
+
async getMolV3000ViaOCL(beautifiedMols: (RDMol | null)[], columnName: string) {
|
|
93
|
+
const beautifiedMolV2000 = beautifiedMols.map((mol) => {
|
|
94
|
+
if (mol === null)
|
|
95
|
+
return '';
|
|
96
|
+
const molBlock = mol.get_molblock();
|
|
97
|
+
mol!.delete();
|
|
98
|
+
return molBlock;
|
|
99
|
+
});
|
|
100
|
+
const molv3000Arr = new Array<string>(beautifiedMolV2000.length);
|
|
101
|
+
const chiralityPb = DG.TaskBarProgressIndicator.create(`Handling chirality...`);
|
|
102
|
+
for (let i = 0; i < beautifiedMolV2000.length; i++) {
|
|
103
|
+
const oclMolecule = OCL.Molecule.fromMolfile(beautifiedMolV2000[i]);
|
|
104
|
+
const molV3000 = oclMolecule.toMolfileV3();
|
|
105
|
+
molv3000Arr[i] = molV3000.replace('STERAC1', 'STEABS');
|
|
106
|
+
const progress = i/beautifiedMolV2000.length*100;
|
|
107
|
+
chiralityPb.update(progress, `${progress?.toFixed(2)}% of molecules completed`);
|
|
108
|
+
}
|
|
109
|
+
chiralityPb.close();
|
|
110
|
+
return DG.Column.fromStrings(columnName, molv3000Arr);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async convertToRdKitBeautifiedMolfileColumn(chiralityEngine?: boolean): Promise<DG.Column<string>> {
|
|
93
114
|
const smiles = await this.getSmilesList();
|
|
94
115
|
const rdKitModule: RDModule = await grok.functions.call('Chem:getRdKitModule');
|
|
95
116
|
const beautifiedMols = smiles.map((item) =>{
|
|
@@ -103,13 +124,16 @@ export class HelmToMolfileConverter {
|
|
|
103
124
|
return mol;
|
|
104
125
|
});
|
|
105
126
|
const columnName = this.df.columns.getUnusedName(`molfile(${this.helmColumn.name})`);
|
|
127
|
+
|
|
128
|
+
if (chiralityEngine)
|
|
129
|
+
return await this.getMolV3000ViaOCL(beautifiedMols, columnName);
|
|
106
130
|
return DG.Column.fromStrings(columnName, beautifiedMols.map((mol) => {
|
|
107
131
|
if (mol === null)
|
|
108
132
|
return '';
|
|
109
133
|
const molBlock = mol.get_v3Kmolblock();
|
|
110
134
|
mol!.delete();
|
|
111
135
|
return molBlock;
|
|
112
|
-
}));
|
|
136
|
+
}));
|
|
113
137
|
}
|
|
114
138
|
|
|
115
139
|
async convertToMolfileV2KColumn(): Promise<DG.Column<string>> {
|
|
@@ -14,7 +14,7 @@ export class MacromoleculeColumnWidget extends DG.Widget {
|
|
|
14
14
|
|
|
15
15
|
private readonly seqCol: DG.Column<string>;
|
|
16
16
|
|
|
17
|
-
private wlViewer: WebLogoViewer;
|
|
17
|
+
private wlViewer: WebLogoViewer | null = null;
|
|
18
18
|
|
|
19
19
|
constructor(seqCol: DG.Column<string>) {
|
|
20
20
|
super(ui.divV([]));
|
|
@@ -46,7 +46,10 @@ export class MacromoleculeColumnWidget extends DG.Widget {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
override detach() {
|
|
49
|
-
this.wlViewer
|
|
49
|
+
if (this.wlViewer) {
|
|
50
|
+
this.wlViewer.detach();
|
|
51
|
+
this.wlViewer = null;
|
|
52
|
+
}
|
|
50
53
|
super.detach();
|
|
51
54
|
}
|
|
52
55
|
}
|
|
@@ -221,7 +221,7 @@ function getHelmCycle(helm: string, source: ConnectionData): string {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
export async function addTransformedColumn(
|
|
224
|
-
molColumn: DG.Column<string>, addHelm: boolean, ruleFiles: string[]
|
|
224
|
+
molColumn: DG.Column<string>, addHelm: boolean, ruleFiles: string[], chiralityEngine?: boolean
|
|
225
225
|
): Promise<void> {
|
|
226
226
|
const df = molColumn.dataFrame;
|
|
227
227
|
const uh = UnitsHandler.getOrCreate(molColumn);
|
|
@@ -243,7 +243,7 @@ export async function addTransformedColumn(
|
|
|
243
243
|
addCommonTags(targetHelmCol);
|
|
244
244
|
targetHelmCol.setTag('units', NOTATION.HELM);
|
|
245
245
|
|
|
246
|
-
const molCol = await getMolColumnFromHelm(df, targetHelmCol);
|
|
246
|
+
const molCol = await getMolColumnFromHelm(df, targetHelmCol, chiralityEngine);
|
|
247
247
|
molCol.name = df.columns.getUnusedName('molfile(' + molColumn.name + ')');
|
|
248
248
|
|
|
249
249
|
if (addHelm) {
|
|
@@ -121,10 +121,12 @@ export class PolyTool {
|
|
|
121
121
|
const addButton = this.getAddButton();
|
|
122
122
|
this.ruleFilesInputs = ui.div(await this.getRuleFilesBlock());
|
|
123
123
|
//const rulesFiles = ui.div(this.ruleFilesInputs);
|
|
124
|
+
const chiralityEngineInput = ui.boolInput('Chirality engine', false);
|
|
124
125
|
|
|
125
126
|
const div = ui.div([
|
|
126
127
|
targetColumnInput,
|
|
127
128
|
generateHelmChoiceInput,
|
|
129
|
+
chiralityEngineInput,
|
|
128
130
|
'Rules used',
|
|
129
131
|
this.ruleFilesInputs,
|
|
130
132
|
addButton
|
|
@@ -138,7 +140,7 @@ export class PolyTool {
|
|
|
138
140
|
grok.shell.warning('No marcomolecule column chosen!');
|
|
139
141
|
return;
|
|
140
142
|
}
|
|
141
|
-
addTransformedColumn(molCol!, generateHelmChoiceInput.value!, this.userRuleSettings.included);
|
|
143
|
+
addTransformedColumn(molCol!, generateHelmChoiceInput.value!, this.userRuleSettings.included, chiralityEngineInput.value!);
|
|
142
144
|
});
|
|
143
145
|
|
|
144
146
|
return this.dialog;
|
|
@@ -26,6 +26,7 @@ import {AggFunc, getAgg} from '../utils/agg';
|
|
|
26
26
|
import {buildCompositionTable} from '../widgets/composition-analysis-widget';
|
|
27
27
|
|
|
28
28
|
import {_package} from '../package';
|
|
29
|
+
import {GAP_SYMBOL} from '../const';
|
|
29
30
|
|
|
30
31
|
declare global {
|
|
31
32
|
interface HTMLCanvasElement {
|
|
@@ -81,12 +82,6 @@ export class PositionMonomerInfo {
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
export class PositionInfo {
|
|
84
|
-
/** Position in sequence */
|
|
85
|
-
public readonly pos: number;
|
|
86
|
-
|
|
87
|
-
/** Position name from column tag*/
|
|
88
|
-
public readonly name: string;
|
|
89
|
-
|
|
90
85
|
private readonly _label: string | undefined;
|
|
91
86
|
public get label(): string { return !!this._label ? this._label : this.name; }
|
|
92
87
|
|
|
@@ -105,11 +100,12 @@ export class PositionInfo {
|
|
|
105
100
|
* @param {number} rowCount Count of elements in column
|
|
106
101
|
* @param {number} sumForHeightCalc Sum of all monomer counts for height calculation
|
|
107
102
|
*/
|
|
108
|
-
constructor(
|
|
103
|
+
constructor(
|
|
104
|
+
/** Position in sequence */ public readonly pos: number,
|
|
105
|
+
/** Position name from column tag*/ public readonly name: string,
|
|
106
|
+
freqs?: { [m: string]: PositionMonomerInfo },
|
|
109
107
|
options?: { sumRowCount?: number, sumValueForHeight?: number, label?: string }
|
|
110
108
|
) {
|
|
111
|
-
this.pos = pos;
|
|
112
|
-
this.name = name;
|
|
113
109
|
this._freqs = freqs ?? {};
|
|
114
110
|
|
|
115
111
|
if (options?.sumRowCount) this.sumRowCount = options.sumRowCount;
|
|
@@ -240,6 +236,8 @@ export class PositionInfo {
|
|
|
240
236
|
}
|
|
241
237
|
|
|
242
238
|
buildCompositionTable(palette: SeqPalette): HTMLTableElement {
|
|
239
|
+
if ('-' in this._freqs)
|
|
240
|
+
throw new Error(`Unexpected monomer symbol '-'.`);
|
|
243
241
|
return buildCompositionTable(palette,
|
|
244
242
|
Object.assign({}, ...Object.entries(this._freqs)
|
|
245
243
|
.map(([m, pmi]) => ({[m]: pmi.rowCount})))
|
|
@@ -616,13 +614,13 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
616
614
|
private getFilter(): DG.BitSet {
|
|
617
615
|
let dfFilterRes: DG.BitSet;
|
|
618
616
|
switch (this.filterSource) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
617
|
+
case FilterSources.Filtered:
|
|
618
|
+
dfFilterRes = this.dataFrame.filter;
|
|
619
|
+
break;
|
|
622
620
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
621
|
+
case FilterSources.Selected:
|
|
622
|
+
dfFilterRes = this.dataFrame.selection.trueCount === 0 ? this.dataFrame.filter : this.dataFrame.selection;
|
|
623
|
+
break;
|
|
626
624
|
}
|
|
627
625
|
return dfFilterRes;
|
|
628
626
|
}
|
|
@@ -816,45 +814,42 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
816
814
|
super.onPropertyChanged(property);
|
|
817
815
|
|
|
818
816
|
switch (property.name) {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
817
|
+
case PROPS.sequenceColumnName:
|
|
818
|
+
this.updateSeqCol();
|
|
819
|
+
break;
|
|
820
|
+
case PROPS.startPositionName:
|
|
821
|
+
case PROPS.endPositionName:
|
|
822
|
+
case PROPS.filterSource:
|
|
823
|
+
case PROPS.shrinkEmptyTail:
|
|
824
|
+
case PROPS.skipEmptyPositions:
|
|
825
|
+
case PROPS.positionHeight: {
|
|
826
|
+
this.render(WlRenderLevel.Freqs, `onPropertyChanged( ${property.name} )`);
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
case PROPS.valueColumnName:
|
|
830
|
+
case PROPS.valueAggrType: {
|
|
831
|
+
this.render(WlRenderLevel.Freqs, `onPropertyChanged( ${property.name} )`);
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
case PROPS.minHeight:
|
|
835
|
+
case PROPS.maxHeight:
|
|
836
|
+
case PROPS.positionWidth:
|
|
837
|
+
case PROPS.showPositionLabels:
|
|
838
|
+
case PROPS.fixWidth:
|
|
839
|
+
case PROPS.fitArea:
|
|
840
|
+
case PROPS.horizontalAlignment:
|
|
841
|
+
case PROPS.verticalAlignment:
|
|
842
|
+
case PROPS.positionMargin:
|
|
843
|
+
case PROPS.positionMarginState: {
|
|
838
844
|
// this.positionWidth obtains a new value
|
|
839
845
|
// this.updateSlider updates this._positionWidth
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
case PROPS.verticalAlignment:
|
|
848
|
-
case PROPS.positionMargin:
|
|
849
|
-
case PROPS.positionMarginState: {
|
|
850
|
-
this.render(WlRenderLevel.Layout, `onPropertyChanged(${property.name})`);
|
|
851
|
-
break;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
case PROPS.backgroundColor: {
|
|
855
|
-
this.render(WlRenderLevel.Render, `onPropertyChanged(${property.name})`);
|
|
856
|
-
break;
|
|
857
|
-
}
|
|
846
|
+
this.render(WlRenderLevel.Layout, `onPropertyChanged(${property.name})`);
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
case PROPS.backgroundColor: {
|
|
850
|
+
this.render(WlRenderLevel.Render, `onPropertyChanged(${property.name})`);
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
858
853
|
}
|
|
859
854
|
}
|
|
860
855
|
|
|
@@ -928,8 +923,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
928
923
|
protected _removeEmptyPositions() {
|
|
929
924
|
if (this.skipEmptyPositions) {
|
|
930
925
|
this.positions = wu(this.positions).filter((pi) => {
|
|
931
|
-
|
|
932
|
-
return !pi.hasMonomer(gapSymbol) || pi.getFreq(gapSymbol).rowCount !== pi.sumRowCount;
|
|
926
|
+
return !pi.hasMonomer(GAP_SYMBOL) || pi.getFreq(GAP_SYMBOL).rowCount !== pi.sumRowCount;
|
|
933
927
|
}).toArray();
|
|
934
928
|
}
|
|
935
929
|
}
|
|
@@ -1004,9 +998,10 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1004
998
|
for (let rowI = 0; rowI < dfRowCount; ++rowI) {
|
|
1005
999
|
if (dfFilter.get(rowI)) {
|
|
1006
1000
|
const seqMList: ISeqSplitted = splitted[rowI];
|
|
1007
|
-
const
|
|
1001
|
+
const om: string = seqMList[this.startPosition + jPos] || this.unitsHandler.defaultGapSymbol;
|
|
1002
|
+
const cm: string = this.unitsHandler?.defaultGapSymbol === om ? GAP_SYMBOL : om;
|
|
1008
1003
|
const pi = this.positions[jPos];
|
|
1009
|
-
const pmi = pi.getFreq(
|
|
1004
|
+
const pmi = pi.getFreq(cm);
|
|
1010
1005
|
++pi.sumRowCount;
|
|
1011
1006
|
pmi.value = ++pmi.rowCount;
|
|
1012
1007
|
}
|
|
@@ -1078,9 +1073,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1078
1073
|
if (this.seqCol && !this.palette) {
|
|
1079
1074
|
this.msgHost!.innerText = `Unknown palette (column semType: '${this.seqCol.semType}').`;
|
|
1080
1075
|
this.msgHost!.style.display = '';
|
|
1081
|
-
} else
|
|
1076
|
+
} else
|
|
1082
1077
|
this.msgHost!.style.display = 'none';
|
|
1083
|
-
}
|
|
1084
1078
|
}
|
|
1085
1079
|
|
|
1086
1080
|
if (!this.seqCol || !this.dataFrame || !this.palette || this.host == null || this.slider == null)
|
|
@@ -1233,9 +1227,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1233
1227
|
tooltipRows.push(ui.div(`${this.valueAggrType}: ${pmi.value.toFixed(3)}`));
|
|
1234
1228
|
const tooltipEl = ui.divV(tooltipRows);
|
|
1235
1229
|
ui.tooltip.show(tooltipEl, args.x + 16, args.y + 16);
|
|
1236
|
-
} else
|
|
1230
|
+
} else
|
|
1237
1231
|
ui.tooltip.hide();
|
|
1238
|
-
}
|
|
1239
1232
|
} catch (err: any) {
|
|
1240
1233
|
const errMsg = errorToConsole(err);
|
|
1241
1234
|
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.canvasOnMouseMove() error:\n` + errMsg);
|
|
@@ -9,6 +9,7 @@ import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
|
9
9
|
import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
|
|
10
10
|
import '../../css/composition-analysis.css';
|
|
11
11
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
12
|
+
import {GAP_SYMBOL} from '../const';
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
export function getCompositionAnalysisWidget(val: DG.SemanticValue): DG.Widget {
|
|
@@ -17,15 +18,15 @@ export function getCompositionAnalysisWidget(val: DG.SemanticValue): DG.Widget {
|
|
|
17
18
|
const alphabet = val.cell.column.tags[bioTAGS.alphabet];
|
|
18
19
|
let palette: SeqPalette = UnknownSeqPalettes.Color;
|
|
19
20
|
switch (alphabet) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
case ALPHABET.DNA:
|
|
22
|
+
case ALPHABET.RNA:
|
|
23
|
+
palette = getPaletteByType(ALPHABET.DNA);
|
|
24
|
+
break;
|
|
25
|
+
case ALPHABET.PT:
|
|
26
|
+
palette = getPaletteByType(ALPHABET.PT);
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
break;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const counts: { [m: string]: number } = {};
|
|
@@ -57,15 +58,21 @@ export function buildCompositionTable(palette: SeqPalette, counts: { [m: string]
|
|
|
57
58
|
const maxRatio = maxValue! / sumValue;
|
|
58
59
|
const elMap: { [m: string]: HTMLElement } = Object.assign({}, ...Array.from(Object.entries(counts))
|
|
59
60
|
.sort((a, b) => b[1] - a[1])
|
|
60
|
-
.map(([
|
|
61
|
+
.map(([cm, value]) => {
|
|
61
62
|
const ratio = value / sumValue;
|
|
62
|
-
const color = palette.get(
|
|
63
|
+
const color = palette.get(cm);
|
|
63
64
|
const barDiv = ui.div('', {classes: 'macromolecule-cell-comp-analysis-bar'});
|
|
64
65
|
barDiv.style.width = `${50 * ratio / maxRatio}px`;
|
|
65
66
|
barDiv.style.backgroundColor = color;
|
|
67
|
+
if (GAP_SYMBOL === cm) {
|
|
68
|
+
barDiv.style.borderWidth = '1px';
|
|
69
|
+
barDiv.style.borderStyle = 'solid';
|
|
70
|
+
barDiv.style.borderColor = DG.Color.toHtml(DG.Color.lightGray);
|
|
71
|
+
}
|
|
72
|
+
const displayMonomer: string = GAP_SYMBOL === cm ? '-' : cm;
|
|
66
73
|
const valueDiv = ui.div(`${(100 * ratio).toFixed(2)}%`);
|
|
67
74
|
const el = ui.div([barDiv, valueDiv], {classes: 'macromolecule-cell-comp-analysis-value'});
|
|
68
|
-
return ({[
|
|
75
|
+
return ({[displayMonomer]: el});
|
|
69
76
|
}));
|
|
70
77
|
|
|
71
78
|
const table = ui.tableFromMap(elMap);
|