@datagrok/bio 2.22.12 → 2.23.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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Davit Rizhinashvili",
6
6
  "email": "drizhinashvili@datagrok.ai"
7
7
  },
8
- "version": "2.22.12",
8
+ "version": "2.23.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",
@@ -44,12 +44,12 @@
44
44
  ],
45
45
  "dependencies": {
46
46
  "@biowasm/aioli": "^3.1.0",
47
- "@datagrok-libraries/bio": "^5.54.7",
48
- "@datagrok-libraries/chem-meta": "^1.2.7",
49
- "@datagrok-libraries/math": "^1.2.4",
50
- "@datagrok-libraries/ml": "^6.10.4",
51
- "@datagrok-libraries/tutorials": "^1.6.1",
52
- "@datagrok-libraries/utils": "^4.6.5",
47
+ "@datagrok-libraries/bio": "^5.55.1",
48
+ "@datagrok-libraries/chem-meta": "^1.2.9",
49
+ "@datagrok-libraries/math": "^1.2.6",
50
+ "@datagrok-libraries/ml": "^6.10.6",
51
+ "@datagrok-libraries/tutorials": "^1.7.4",
52
+ "@datagrok-libraries/utils": "^4.6.9",
53
53
  "@webgpu/types": "^0.1.40",
54
54
  "ajv": "^8.12.0",
55
55
  "ajv-errors": "^3.0.0",
@@ -44,6 +44,13 @@ export namespace funcs {
44
44
  return await grok.functions.call('Bio:StandardiseMonomerLibrary', { library });
45
45
  }
46
46
 
47
+ /**
48
+ Matches molecules in a column with monomers from the selected library(s)
49
+ */
50
+ export async function matchWithMonomerLibrary(table: DG.DataFrame , molecules: DG.Column , polymerType: string ): Promise<void> {
51
+ return await grok.functions.call('Bio:MatchWithMonomerLibrary', { table, molecules, polymerType });
52
+ }
53
+
47
54
  export async function getBioLib(): Promise<any> {
48
55
  return await grok.functions.call('Bio:GetBioLib', {});
49
56
  }
package/src/package.g.ts CHANGED
@@ -110,6 +110,23 @@ export function separatorSequenceCellRenderer() : any {
110
110
  return PackageFunctions.separatorSequenceCellRenderer();
111
111
  }
112
112
 
113
+ //tags: cellRenderer
114
+ //output: grid_cell_renderer result
115
+ //meta.cellType: sequence
116
+ //meta.columnTags: quality=Macromolecule, units=biln
117
+ export function bilnSequenceCellRenderer() : any {
118
+ return PackageFunctions.bilnSequenceCellRenderer();
119
+ }
120
+
121
+ //tags: notationRefiner
122
+ //input: column col
123
+ //input: object stats
124
+ //input: string separator { nullable: true; optional: true }
125
+ //output: bool result
126
+ export function refineNotationProviderForBiln(col: DG.Column<any>, stats: any, separator: any) : boolean {
127
+ return PackageFunctions.refineNotationProviderForBiln(col, stats, separator);
128
+ }
129
+
113
130
  //name: Bioinformatics | Sequence Renderer
114
131
  //tags: panel
115
132
  //input: column molColumn { semType: Macromolecule }
@@ -327,7 +344,7 @@ export function importBam(fileContent: string) : any {
327
344
  return PackageFunctions.importBam(fileContent);
328
345
  }
329
346
 
330
- //top-menu: Bio | Transform | Convert Notation...
347
+ //top-menu: Bio | Transform | Convert Sequence Notation...
331
348
  export function convertDialog() : void {
332
349
  PackageFunctions.convertDialog();
333
350
  }
package/src/package.ts CHANGED
@@ -30,7 +30,7 @@ import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/sr
30
30
  import {ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
31
31
  import {RDModule as _RDMoule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
32
32
  import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
33
- import {ISeqHandler} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
33
+ import {ISeqHandler, SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
34
34
  import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
35
35
 
36
36
  import {getMacromoleculeColumns} from './utils/ui-utils';
@@ -77,6 +77,7 @@ import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomi
77
77
  import {molecular3DStructureWidget, toAtomicLevelWidget} from './widgets/to-atomic-level-widget';
78
78
  import {handleSequenceHeaderRendering} from './widgets/sequence-scrolling-widget';
79
79
  import {PolymerType} from '@datagrok-libraries/js-draw-lite/src/types/org';
80
+ import {BilnNotationProvider} from './utils/biln';
80
81
  export const _package = new BioPackage(/*{debug: true}/**/);
81
82
  export * from './package.g';
82
83
 
@@ -297,6 +298,49 @@ export class PackageFunctions {
297
298
  return new MacromoleculeSequenceCellRenderer();
298
299
  }
299
300
 
301
+ @grok.decorators.func({
302
+ name: 'bilnSequenceCellRenderer',
303
+ tags: ['cellRenderer'],
304
+ meta: {
305
+ cellType: 'sequence',
306
+ columnTags: 'quality=Macromolecule, units=biln'
307
+ },
308
+ outputs: [{type: 'grid_cell_renderer', name: 'result'}]
309
+ })
310
+ static bilnSequenceCellRenderer(): MacromoleculeSequenceCellRenderer {
311
+ return new MacromoleculeSequenceCellRenderer();
312
+ }
313
+
314
+ @grok.decorators.func({
315
+ name: 'refineNotationProviderForBiln',
316
+ tags: ['notationRefiner'],
317
+ outputs: [{type: 'bool', name: 'result'}]
318
+ })
319
+ static refineNotationProviderForBiln(
320
+ @grok.decorators.param({type: 'column'}) col: DG.Column<string>,
321
+ @grok.decorators.param({type: 'object'}) stats: {freq: { [key: string]: number; }, sameLength: boolean},
322
+ @grok.decorators.param({type: 'string', options: {nullable: true, optional: true}}) separator: string | null
323
+ ): boolean {
324
+ if (separator !== '-')
325
+ return false;// biln uses '-' as a separator
326
+ const reCons = Object.keys(stats.freq).some((om) => om.match(/^.+\(\d{1,2},\d{1,2}\)$/));
327
+ if (!reCons) {
328
+ // biln might also encode monomers with hyphens in names encoded by []
329
+ // here we know that there are no monomers with connections like (1,2) in names, so we can check for []
330
+ const reBrackets = Object.keys(stats.freq).some((om) => om.includes('[') || om.includes(']'));
331
+ if (!reBrackets)
332
+ return false;
333
+ }
334
+ // refine the notation provider
335
+ col.setTag('aligned', 'SEQ');
336
+ col.setTag('alphabet', 'UN');
337
+ col.setTag('.alphabetIsMultichar', 'true');
338
+ col.meta.units = NOTATION.BILN;
339
+ col.temp[SeqTemps.notationProvider] = new BilnNotationProvider(separator, _package.seqHelper, col);
340
+
341
+ return true;
342
+ }
343
+
300
344
  // // -- Property panels --
301
345
 
302
346
  @grok.decorators.panel({name: 'Bioinformatics | Sequence Renderer'})
@@ -757,7 +801,7 @@ export class PackageFunctions {
757
801
 
758
802
  @grok.decorators.func({
759
803
  name: 'convertDialog',
760
- 'top-menu': 'Bio | Transform | Convert Notation...'
804
+ 'top-menu': 'Bio | Transform | Convert Sequence Notation...'
761
805
  })
762
806
  static convertDialog() {
763
807
  const col: DG.Column<string> | undefined = getMacromoleculeColumns()[0];
@@ -0,0 +1,167 @@
1
+ /* eslint-disable max-len */
2
+ /* eslint-disable max-lines */
3
+ /* eslint-disable max-lines-per-function */
4
+ import * as grok from 'datagrok-api/grok';
5
+ import * as ui from 'datagrok-api/ui';
6
+ import * as DG from 'datagrok-api/dg';
7
+
8
+ import {category, test, expect, before} from '@datagrok-libraries/utils/src/test';
9
+
10
+ import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
11
+ import {ISeqHelper, getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
12
+
13
+ import {_testNeg, _testPos, DetectorTestData, DfReaderFunc, PosCol} from './utils/detectors-utils';
14
+ import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
15
+
16
+ export async function prepareBiln(list: string[], seqHelper: ISeqHelper): Promise<DG.Column> {
17
+ const col: DG.Column = DG.Column.fromList(DG.TYPE.STRING, 'seq', list);
18
+ const semType: string = await grok.functions.call('Bio:detectMacromolecule', {col: col});
19
+ if (semType)
20
+ col.semType = semType;
21
+ expect(col.semType, DG.SEMTYPE.MACROMOLECULE);
22
+ const sh = seqHelper.getSeqHandler(col);
23
+ await sh.refinerPromise; // wait for refiner to finish
24
+ const _newSh = seqHelper.getSeqHandler(col);
25
+ return col;
26
+ }
27
+
28
+
29
+ export async function _testBilnDetection(list: string[], seqHelper: ISeqHelper, negativeTest = false): Promise<void> {
30
+ const col = await prepareBiln(list, seqHelper);
31
+ expect(col.meta.units === NOTATION.BILN, !negativeTest, `Incorrectly detected as ${col.meta.units}`);
32
+ expect(col.temp[SeqTemps.notationProvider] != null, !negativeTest, `No notation provider for BILN`);
33
+ }
34
+
35
+ export async function _testBilnToHelm(list: string[], expectedHelm: string[], seqHelper: ISeqHelper): Promise<void> {
36
+ const col = await prepareBiln(list, seqHelper);
37
+ const sh = seqHelper.getSeqHandler(col);
38
+ for (let i = 0; i < list.length; i++) {
39
+ const helm = sh.getHelm(i);
40
+ expect(helm === expectedHelm[i], true, `Incorrect HELM conversion for ${list[i]}: Expected ${expectedHelm[i]} \n Got ${helm}`);
41
+ }
42
+ // also test through converter
43
+ const converter = sh.getConverter(NOTATION.HELM);
44
+ for (let i = 0; i < list.length; i++) {
45
+ const helm = converter(list[i]);
46
+ expect(helm === expectedHelm[i], true, `Incorrect HELM conversion for ${list[i]}: Expected ${expectedHelm[i]} \n Got ${helm}`);
47
+ }
48
+ }
49
+
50
+ export async function _testHelmToBiln(helmList: string[], expectedBiln: string[], seqHelper: ISeqHelper): Promise<void> {
51
+ const col: DG.Column = DG.Column.fromList(DG.TYPE.STRING, 'helm', helmList);
52
+ const df = DG.DataFrame.fromColumns([col]);
53
+ await df.meta.detectSemanticTypes();
54
+ await grok.data.detectSemanticTypes(df);
55
+ expect(col.semType === DG.SEMTYPE.MACROMOLECULE, true, `Incorrectly detected as ${col.semType}`);
56
+ expect(col.meta.units === NOTATION.HELM, true, `Incorrectly detected as ${col.meta.units}`);
57
+ const sh = seqHelper.getSeqHandler(col);
58
+ const converter = sh.getConverter(NOTATION.BILN);
59
+ for (let i = 0; i < helmList.length; i++) {
60
+ const biln = converter(helmList[i]);
61
+ expect(biln === expectedBiln[i], true, `Incorrect BILN conversion for ${helmList[i]}: Expected ${expectedBiln[i]} \n Got ${biln}`);
62
+ }
63
+ }
64
+
65
+ export const detectorTestsDataForBiln: {name: string, seqs: string[], negative: boolean}[] = [
66
+ {
67
+ name: 'Valid Biln',
68
+ seqs: [
69
+ 'A-C(1,3)-G-G-H-A-V-E-A-K-Y-L-V-C(3,3)-S.G-I-V-E-A-C(2,3)-C(1,3)-T-S-I-C(2,3)-S-L-Y-Q-L-E-N-Y-C(3,3)-Y',
70
+ 'A-C(1,3)-G-G-H-A-V-E-A-K-Y-L-V-C(3,3)-S.G-I-V-E-A-C(2,3)-C(1,3)-T-S-I-C(2,3)-S-L-Y-Q-L-E-N-Y-C(3,3)-Y',
71
+ 'C-C(1,3)-S-W-P-A-R-C(2,3)-L-H-Q-D-L-C(3,3)-NH2.C(1,1)(2,2)(3,3)',
72
+ 'C-C(1,3)-S-W-P-A-R-C(2,3)-L-H-Q-D-L-C(3,3)-NH2.[C](1,1)(2,2)(3,3)',
73
+ 'D-T-H-F-P-I-C(1,3)-I-F-C(2,3)-C(3,3)-G-C(2,3)-C(4,3)-H-R-S-K-C(3,3)-G-M-C(4,3)-C(1,3)-K-T'
74
+ ], negative: false
75
+ }, {
76
+ name: 'Simple Separator Neg',
77
+ seqs: [
78
+ 'meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me',
79
+ 'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Phe_ab-dehydro/N/D-Orn/D-aThr//Phe_4Me',
80
+ 'Lys_Boc/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Thr_PO3H2/N/D-Orn/D-aThr//Phe_4Me',
81
+ 'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Thr_PO3H2/N/D-Orn/D-aThr//Phe_4Me',
82
+ 'meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/Chg/N/D-Orn/D-aThr//Phe_4Me'
83
+ ], negative: true
84
+ }, {
85
+ name: 'Valid Biln without cyclization',
86
+ seqs: [
87
+ 'meI-hHis-Aca-N-T-dE-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-E-N-[D-Orn]-[D-aThr]--Phe_4Me',
88
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-[Phe_ab-dehydro]-N-[D-Orn]-[D-aThr]--Phe_4Me',
89
+ 'Lys_Boc-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
90
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
91
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-Chg-N-[D-Orn]-[D-aThr]--Phe_4Me',
92
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-Tyr_Bn-dV-E-N-dV---Phe_4Me',
93
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-Aze-dV-E-N-dV---Phe_4Me',
94
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-meQ-dV-E-N-dV---Phe_4Me'
95
+ ], negative: false
96
+ }
97
+ ];
98
+
99
+ export const bilnToHelmTestsData: {name: string, biln: string[], helm: string[]}[] = [
100
+ {
101
+ name: 'Linear',
102
+ biln: ['meI-hHis-Aca-N-T-dE-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-E-N-[D-Orn]-[D-aThr]--Phe_4Me',
103
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-[Phe_ab-dehydro]-N-[D-Orn]-[D-aThr]--Phe_4Me',
104
+ 'Lys_Boc-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
105
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
106
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-Chg-N-[D-Orn]-[D-aThr]--Phe_4Me'],
107
+ helm: [
108
+ 'PEPTIDE1{[meI].[hHis].[Aca].N.T.[dE].[Thr_PO3H2].[Aca].[D-Tyr_Et].[Tyr_ab-dehydroMe].[dV].E.N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
109
+ 'PEPTIDE1{[meI].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Phe_ab-dehydro].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
110
+ 'PEPTIDE1{[Lys_Boc].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Thr_PO3H2].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
111
+ 'PEPTIDE1{[meI].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Thr_PO3H2].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
112
+ 'PEPTIDE1{[meI].[hHis].[Aca].N.T.[dK].[Thr_PO3H2].[Aca].[D-Tyr_Et].[Tyr_ab-dehydroMe].[dV].[Chg].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$'
113
+ ]
114
+ }, {
115
+ name: 'Cyclic',
116
+ biln: [
117
+ 'C-C(1,3)-S-W-P-A-R-C(2,3)-L-H-Q-D-L-C(3,3)-NH2.[C](1,1)(2,2)(3,3)',
118
+ 'D-T-H-F-P-I-C(1,3)-I-F-C(2,3)-C(3,3)-G-C(2,3)-C(4,3)-H-R-S-K-C(3,3)-G-M-C(4,3)-C(1,3)-K-T',
119
+ 'L-C(1,3)-G-S-H-L-V-E-A-L-Y-L-V-C(2,3)-G.G-I-V-E-Q-C(3,3)-C(1,3)-T-S-I-C(3,3)-S-L-Y-Q-L-E-N-Y-C(2,3)-N',
120
+ 'H-Aib-E-G-T-F-T-S-D(2,3)-V-S-S-Y-L-E-G-Q-A-A-K(1,3)-E-F-I-A-W-L-V-R-G-R-G.C(2,3)-gGlu-G-G(1,2)',
121
+ 'F(4,2).dI(1,1)(3,3)-Trp_Ome-Asp_OMe-Cys_Bn-meG-Phe_3Cl-dD-T-dI(4,3)-T-dK-aG-3Pal-xiIle-meD-Ala_tBu(1,2).L(2,1)-Pro_4Me3OH-S-NMe2Abz-Q-3Pal-xiIle-D-Hyp-Ala_tBu-dI(3,3)-Trp_Ome-Asp_OMe-N-meG-Phe_34diCl-Phe_34diCl(2,2)'
122
+ ],
123
+ helm: [
124
+ 'PEPTIDE1{C.C.S.W.P.A.R.C.L.H.Q.D.L.C.[NH2]}|PEPTIDE2{C}$PEPTIDE1,PEPTIDE2,14:R3-1:R3|PEPTIDE1,PEPTIDE2,8:R3-1:R2|PEPTIDE1,PEPTIDE2,2:R3-1:R1$$$V2.0',
125
+ 'PEPTIDE1{D.T.H.F.P.I.C.I.F.C.C.G.C.C.H.R.S.K.C.G.M.C.C.K.T}$PEPTIDE1,PEPTIDE1,10:R3-13:R3|PEPTIDE1,PEPTIDE1,11:R3-19:R3|PEPTIDE1,PEPTIDE1,14:R3-22:R3|PEPTIDE1,PEPTIDE1,7:R3-23:R3$$$V2.0',
126
+ 'PEPTIDE1{L.C.G.S.H.L.V.E.A.L.Y.L.V.C.G}|PEPTIDE2{G.I.V.E.Q.C.C.T.S.I.C.S.L.Y.Q.L.E.N.Y.C.N}$PEPTIDE1,PEPTIDE2,2:R3-7:R3|PEPTIDE2,PEPTIDE2,6:R3-11:R3|PEPTIDE1,PEPTIDE2,14:R3-20:R3$$$V2.0',
127
+ 'PEPTIDE1{H.[Aib].E.G.T.F.T.S.D.V.S.S.Y.L.E.G.Q.A.A.K.E.F.I.A.W.L.V.R.G.R.G}|PEPTIDE2{C.[gGlu].G.G}$PEPTIDE1,PEPTIDE2,9:R3-1:R3|PEPTIDE1,PEPTIDE2,20:R3-4:R2$$$V2.0',
128
+ 'PEPTIDE1{F}|PEPTIDE2{[dI].[Trp_Ome].[Asp_OMe].[Cys_Bn].[meG].[Phe_3Cl].[dD].T.[dI].T.[dK].[aG].[3Pal].[xiIle].[meD].[Ala_tBu]}|PEPTIDE3{L.[Pro_4Me3OH].S.[NMe2Abz].Q.[3Pal].[xiIle].D.[Hyp].[Ala_tBu].[dI].[Trp_Ome].[Asp_OMe].N.[meG].[Phe_34diCl].[Phe_34diCl]}$PEPTIDE1,PEPTIDE2,1:R2-9:R3|PEPTIDE2,PEPTIDE2,1:R1-16:R2|PEPTIDE2,PEPTIDE3,1:R3-11:R3|PEPTIDE3,PEPTIDE3,1:R1-17:R2$$$V2.0'
129
+ ]
130
+ }
131
+ ];
132
+
133
+ export const helmToBilnTestsData: {name: string, helm: string[], biln: string[]}[] = [
134
+ {
135
+ name: 'Linear',
136
+ biln: [
137
+ 'meI-hHis-Aca-N-T-dE-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-E-N-[D-Orn]-[D-aThr]--Phe_4Me',
138
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-[Phe_ab-dehydro]-N-[D-Orn]-[D-aThr]--Phe_4Me',
139
+ 'Lys_Boc-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
140
+ 'meI-hHis-Aca-Cys_SEt-T-dK-Thr_PO3H2-Aca-Tyr_PO3H2-[D-Chg]-dV-Thr_PO3H2-N-[D-Orn]-[D-aThr]--Phe_4Me',
141
+ 'meI-hHis-Aca-N-T-dK-Thr_PO3H2-Aca-[D-Tyr_Et]-[Tyr_ab-dehydroMe]-dV-Chg-N-[D-Orn]-[D-aThr]--Phe_4Me'
142
+ ],
143
+ helm: [
144
+ 'PEPTIDE1{[meI].[hHis].[Aca].N.T.[dE].[Thr_PO3H2].[Aca].[D-Tyr_Et].[Tyr_ab-dehydroMe].[dV].E.N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
145
+ 'PEPTIDE1{[meI].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Phe_ab-dehydro].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
146
+ 'PEPTIDE1{[Lys_Boc].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Thr_PO3H2].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
147
+ 'PEPTIDE1{[meI].[hHis].[Aca].[Cys_SEt].T.[dK].[Thr_PO3H2].[Aca].[Tyr_PO3H2].[D-Chg].[dV].[Thr_PO3H2].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$',
148
+ 'PEPTIDE1{[meI].[hHis].[Aca].N.T.[dK].[Thr_PO3H2].[Aca].[D-Tyr_Et].[Tyr_ab-dehydroMe].[dV].[Chg].N.[D-Orn].[D-aThr].*.[Phe_4Me]}$$$$'
149
+ ]
150
+ }, {
151
+ name: 'Cyclic',
152
+ biln: [
153
+ 'C-C(3,3)-S-W-P-A-R-C(2,3)-L-H-Q-D-L-C(1,3)-NH2.C(1,3)(2,2)(3,1)',
154
+ 'D-T-H-F-P-I-C(4,3)-I-F-C(1,3)-C(2,3)-G-C(1,3)-C(3,3)-H-R-S-K-C(2,3)-G-M-C(3,3)-C(4,3)-K-T',
155
+ 'L-C(1,3)-G-S-H-L-V-E-A-L-Y-L-V-C(3,3)-G.G-I-V-E-Q-C(2,3)-C(1,3)-T-S-I-C(2,3)-S-L-Y-Q-L-E-N-Y-C(3,3)-N',
156
+ 'H-Aib-E-G-T-F-T-S-D(1,3)-V-S-S-Y-L-E-G-Q-A-A-K(2,3)-E-F-I-A-W-L-V-R-G-R-G.C(1,3)-gGlu-G-G(2,2)',
157
+ 'F(1,2).dI(2,1)(3,3)-Trp_Ome-Asp_OMe-Cys_Bn-meG-Phe_3Cl-dD-T-dI(1,3)-T-dK-aG-3Pal-xiIle-meD-Ala_tBu(2,2).L(4,1)-Pro_4Me3OH-S-NMe2Abz-Q-3Pal-xiIle-D-Hyp-Ala_tBu-dI(3,3)-Trp_Ome-Asp_OMe-N-meG-Phe_34diCl-Phe_34diCl(4,2)'
158
+ ],
159
+ helm: [
160
+ 'PEPTIDE1{C.C.S.W.P.A.R.C.L.H.Q.D.L.C.[NH2]}|PEPTIDE2{C}$PEPTIDE1,PEPTIDE2,14:R3-1:R3|PEPTIDE1,PEPTIDE2,8:R3-1:R2|PEPTIDE1,PEPTIDE2,2:R3-1:R1$$$V2.0',
161
+ 'PEPTIDE1{D.T.H.F.P.I.C.I.F.C.C.G.C.C.H.R.S.K.C.G.M.C.C.K.T}$PEPTIDE1,PEPTIDE1,10:R3-13:R3|PEPTIDE1,PEPTIDE1,11:R3-19:R3|PEPTIDE1,PEPTIDE1,14:R3-22:R3|PEPTIDE1,PEPTIDE1,7:R3-23:R3$$$V2.0',
162
+ 'PEPTIDE1{L.C.G.S.H.L.V.E.A.L.Y.L.V.C.G}|PEPTIDE2{G.I.V.E.Q.C.C.T.S.I.C.S.L.Y.Q.L.E.N.Y.C.N}$PEPTIDE1,PEPTIDE2,2:R3-7:R3|PEPTIDE2,PEPTIDE2,6:R3-11:R3|PEPTIDE1,PEPTIDE2,14:R3-20:R3$$$V2.0',
163
+ 'PEPTIDE1{H.[Aib].E.G.T.F.T.S.D.V.S.S.Y.L.E.G.Q.A.A.K.E.F.I.A.W.L.V.R.G.R.G}|PEPTIDE2{C.[gGlu].G.G}$PEPTIDE1,PEPTIDE2,9:R3-1:R3|PEPTIDE1,PEPTIDE2,20:R3-4:R2$$$V2.0',
164
+ 'PEPTIDE1{F}|PEPTIDE2{[dI].[Trp_Ome].[Asp_OMe].[Cys_Bn].[meG].[Phe_3Cl].[dD].T.[dI].T.[dK].[aG].[3Pal].[xiIle].[meD].[Ala_tBu]}|PEPTIDE3{L.[Pro_4Me3OH].S.[NMe2Abz].Q.[3Pal].[xiIle].D.[Hyp].[Ala_tBu].[dI].[Trp_Ome].[Asp_OMe].N.[meG].[Phe_34diCl].[Phe_34diCl]}$PEPTIDE1,PEPTIDE2,1:R2-9:R3|PEPTIDE2,PEPTIDE2,1:R1-16:R2|PEPTIDE2,PEPTIDE3,1:R3-11:R3|PEPTIDE3,PEPTIDE3,1:R1-17:R2$$$V2.0'
165
+ ]
166
+ }
167
+ ];
@@ -1,3 +1,5 @@
1
+ /* eslint-disable max-lines */
2
+ /* eslint-disable max-lines-per-function */
1
3
  import * as DG from 'datagrok-api/dg';
2
4
  import * as grok from 'datagrok-api/grok';
3
5
 
@@ -7,6 +9,7 @@ import {ISeqHelper, getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-he
7
9
  import {ISeqHandler} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
8
10
 
9
11
  import {ConverterFunc} from './types';
12
+ import {_testBilnToHelm, _testHelmToBiln, bilnToHelmTestsData, helmToBilnTestsData} from './biln-tests';
10
13
 
11
14
 
12
15
  category('converters', () => {
@@ -287,4 +290,15 @@ RNA1{p.r(U)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.r(U)p.r(U)p.r(C)p.r(A)p.r(A)p.r(C)p.p
287
290
  test('testHelmLonePhosphorus', async () => {
288
291
  await _testConvert(Samples.helmLonePhosphorus, converter(NOTATION.FASTA), Samples.fastaRna);
289
292
  });
293
+
294
+ for (const sample of bilnToHelmTestsData) {
295
+ test(`testBilnToHelm_${sample.name}`, async () => {
296
+ await _testBilnToHelm(sample.biln, sample.helm, seqHelper);
297
+ });
298
+ }
299
+ for (const sample of helmToBilnTestsData) {
300
+ test(`testHelmToBiln_${sample.name}`, async () => {
301
+ await _testHelmToBiln(sample.helm, sample.biln, seqHelper);
302
+ });
303
+ }
290
304
  });
@@ -10,6 +10,8 @@ import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-librarie
10
10
  import {ISeqHelper, getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
11
11
 
12
12
  import {_testNeg, _testPos, DetectorTestData, DfReaderFunc, PosCol} from './utils/detectors-utils';
13
+ import { SeqTemps } from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
14
+ import { _testBilnDetection, detectorTestsDataForBiln } from './biln-tests';
13
15
 
14
16
  /*
15
17
  // snippet to list df columns of semType='Macromolecule' (false positive)
@@ -418,6 +420,11 @@ MWRSWY-CKHPMWRSWY-CKHP`;
418
420
  }, seqHelper);
419
421
  });
420
422
 
423
+ for (const bilnT of detectorTestsDataForBiln) {
424
+ test(bilnT.name, async () => {
425
+ await _testBilnDetection(bilnT.seqs, seqHelper, bilnT.negative);
426
+ });
427
+ }
421
428
  // test('samplesFastaFasta', async () => {
422
429
  // await _testDf(readSamples(Samples.fastaFasta), {
423
430
  // 'sequence': new PosCol(NOTATION.FASTA, ALIGNMENT.SEQ, ALPHABET.PT, 20, false),
@@ -35,7 +35,7 @@ category('PepSeA', () => {
35
35
  const tgtMsaCol = df.getCol('MSA');
36
36
  for (let i = 0; i < resMsaCol!.length; ++i)
37
37
  expect(resMsaCol!.get(i) == tgtMsaCol.get(i), true);
38
- }, {timeout: 60000 /* docker */, stressTest: true, skipReason: 'Fails in docker'});
38
+ }, {timeout: 60000 /* docker */, skipReason: 'Fails in docker'});
39
39
 
40
40
  test('stderr', async () => {
41
41
  const logger = new TestLogger();
@@ -45,7 +45,7 @@ category('PepSeA', () => {
45
45
  const tgtMsaCol = df.getCol('MSA');
46
46
  expectArray(resMsaCol!.toList(), tgtMsaCol.toList());
47
47
  expect(logger.warningList[0].message, pepseaStderrWarningList);
48
- }, {timeout: 60000 /* docker */, stressTest: true, skipReason: 'Fails in docker'});
48
+ }, {timeout: 60000 /* docker */, skipReason: 'Fails in docker'});
49
49
 
50
50
  test('error', async () => {
51
51
  const logger = new TestLogger();
@@ -0,0 +1,69 @@
1
+ /* eslint-disable max-len */
2
+ /* eslint-disable max-len */
3
+ import * as grok from 'datagrok-api/grok';
4
+ import * as ui from 'datagrok-api/ui';
5
+ import * as DG from 'datagrok-api/dg';
6
+
7
+ /* eslint-disable max-len */
8
+ import {ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
9
+ import {INotationProvider, SplitterFunc} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
10
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
11
+ import {CellRendererBackBase} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
12
+ import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
13
+ import {monomerToShort, splitterAsBiln} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
14
+ import {_package} from '../package';
15
+ /* eslint-enable max-len */
16
+
17
+ export class BilnNotationProvider implements INotationProvider {
18
+ public readonly splitter: SplitterFunc;
19
+
20
+ get defaultGapOriginal(): string { return ''; }
21
+
22
+ constructor(
23
+ public readonly separator: string,
24
+ public readonly seqHelper: ISeqHelper,
25
+ public readonly seqCol: DG.Column
26
+ ) {
27
+ this.splitter = splitterAsBiln.bind(this);
28
+ }
29
+
30
+ setUnits(): void {}
31
+
32
+ public getHelm(seq: string, _options?: any): string {
33
+ // return resPseudoHelm;
34
+ // generate helm from biln
35
+ const seqSplitted = this.splitter(seq);
36
+ const sh = this.seqHelper.getSeqHandler(this.seqCol);
37
+ return sh.getJoiner({notation: NOTATION.HELM})(seqSplitted);
38
+ }
39
+
40
+ public createCellRendererBack(gridCol: DG.GridColumn | null, tableCol: DG.Column<string>):
41
+ CellRendererBackBase<string> {
42
+ const maxLengthOfMonomer = _package.properties.maxMonomerLength || 4;
43
+ // (_package.bioProperties ? _package.bioProperties.maxMonomerLength : 4) ?? 50;
44
+ const back = new BilnCellRendererBack(gridCol, tableCol,
45
+ maxLengthOfMonomer, this.seqHelper);
46
+
47
+ back.init().then(() => {});
48
+ return back;
49
+ }
50
+ }
51
+
52
+ export class BilnCellRendererBack extends MonomerPlacer {
53
+ constructor(
54
+ gridCol: DG.GridColumn | null, tableCol: DG.Column,
55
+ maxLengthOfMonomer: number, seqHelper: ISeqHelper
56
+ ) {
57
+ super(gridCol, tableCol, _package.logger, maxLengthOfMonomer, () => {
58
+ const sh = seqHelper.getSeqHandler(tableCol);
59
+ const {font, fontWidth} = MonomerPlacer.getFontSettings(tableCol);
60
+ return {
61
+ seqHandler: sh,
62
+ font: font,
63
+ fontCharWidth: fontWidth,
64
+ separatorWidth: 0,
65
+ monomerToShort: monomerToShort,
66
+ };
67
+ });
68
+ }
69
+ }
@@ -81,10 +81,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
81
81
 
82
82
  getRendererBack(gridCell: DG.GridCell): CellRendererBackBase<string> | null {
83
83
  const [gridCol, tableCol, _temp] = getGridCellColTemp<string, any>(gridCell);
84
- if (tableCol.meta.units !== NOTATION.CUSTOM)
84
+ if (_temp.rendererBack)
85
85
  return _temp.rendererBack;
86
86
  let back: CellRendererBackBase<string> | null = null;
87
-
88
87
  if (this.seqHelper) {
89
88
  const sh = this.seqHelper.getSeqHandler(tableCol);
90
89
  back = sh.getRendererBack(gridCol, tableCol);
@@ -96,10 +95,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
96
95
  const colTemp: TempType = gridCell.cell.column.temp;
97
96
  colTemp[tempTAGS.currentWord] = gridCell.cell.value;
98
97
  gridCell.grid.invalidate();
99
- if (gridCell.cell.column.meta.units === NOTATION.CUSTOM) {
100
- const back = this.getRendererBack(gridCell);
101
- back?.onClick(gridCell, _e);
102
- }
98
+ const back = this.getRendererBack(gridCell);
99
+ back?.onClick(gridCell, _e);
103
100
  }
104
101
 
105
102
  override onMouseEnter(gridCell: DG.GridCell, e: MouseEvent) {
@@ -195,12 +192,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
195
192
  }
196
193
 
197
194
  override render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell, cellStyle: DG.GridCellStyle): void {
198
- if (gridCell.cell.column?.meta?.units === NOTATION.CUSTOM) {
199
- const back = this.getRendererBack(gridCell);
195
+ const back = this.getRendererBack(gridCell);
196
+ if (back)
200
197
  back?.render(g, x, y, w, h, gridCell, cellStyle);
201
- return;
202
- }
203
- this.renderInt(g, x, y, w, h, gridCell, cellStyle);
198
+ else
199
+ this.renderInt(g, x, y, w, h, gridCell, cellStyle);
204
200
  }
205
201
  }
206
202
 
@@ -39,6 +39,7 @@ export function convert(col: DG.Column<string> | undefined, seqHelper: ISeqHelpe
39
39
  NOTATION.FASTA,
40
40
  NOTATION.SEPARATOR,
41
41
  NOTATION.HELM,
42
+ NOTATION.BILN
42
43
  ];
43
44
  const toggleColumn = (newCol: DG.Column) => {
44
45
  srcCol = newCol;
@@ -47,7 +48,7 @@ export function convert(col: DG.Column<string> | undefined, seqHelper: ISeqHelpe
47
48
  if (currentNotation === NOTATION.HELM)
48
49
  separatorInput.value = '/'; // helm monomers can have - in the name like D-aThr;
49
50
  dialogHeader.textContent = 'Current notation: ' + currentNotation;
50
- filteredNotations = notations.filter((e) => e !== currentNotation);
51
+ filteredNotations = notations;//.filter((e) => e !== currentNotation); TEMPORARY DO NOT FORGET TO UNCOMMENT
51
52
  targetNotationInput = ui.input.choice('Convert to', {
52
53
  value: filteredNotations[0], items: filteredNotations,
53
54
  onValueChanged: toggleSeparator
@@ -70,7 +71,7 @@ export function convert(col: DG.Column<string> | undefined, seqHelper: ISeqHelpe
70
71
  });
71
72
 
72
73
  const separatorArray = ['-', '.', '/'];
73
- let filteredNotations = notations.filter((e) => e !== currentNotation);
74
+ let filteredNotations = notations;//.filter((e) => e !== currentNotation); // TEMPORARY DO NOT FORGET TO UNCOMMENT
74
75
 
75
76
  const separatorInput = ui.input.choice('Separator', {value: separatorArray[0], items: separatorArray});
76
77
 
@@ -55,7 +55,7 @@ export class Helm {
55
55
  private getSimplePolymerByMonomerIdx(monomerGlobalIdx: number): SimplePolymer {
56
56
  const shifts = this.getMonomerIdxShifts();
57
57
  const shiftValues = Object.values(shifts);
58
- const lowerBound = shiftValues.sort((a, b) => a - b).find(
58
+ const lowerBound = shiftValues.sort((a, b) => b - a).find( // find the largest shift not exceeding monomerGlobalIdx
59
59
  (shift) => monomerGlobalIdx >= shift
60
60
  );
61
61
  if (lowerBound === undefined)
@@ -11,6 +11,10 @@ import {_package} from '../package';
11
11
 
12
12
  /** Used in Macromolecule column tooltip */
13
13
  export class MacromoleculeColumnWidget extends DG.Widget {
14
+ get type(): string {
15
+ return 'MacromoleculeColumnWidget';
16
+ }
17
+
14
18
  private viewed: boolean = false;
15
19
 
16
20
  private wlViewer: WebLogoViewer | null = null;
@@ -3,14 +3,15 @@ import * as DG from 'datagrok-api/dg';
3
3
  import {GridCell} from 'datagrok-api/dg';
4
4
  import * as ui from 'datagrok-api/ui';
5
5
  import {ALPHABET, monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
- import {GAP_SYMBOL, MONOMER_MOTIF_SPLITTER, TAGS as bioTAGS,} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
6
+ import {BioTags, GAP_SYMBOL, MONOMER_MOTIF_SPLITTER, TAGS as bioTAGS,} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
7
7
  import {MONOMER_RENDERER_TAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
8
8
  import {getGridCellColTemp} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
9
9
 
10
10
  import {CellRendererWithMonomerLibBackBase} from './monomer-cell-renderer-base';
11
11
  import * as C from './constants';
12
12
  import {undefinedColor} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
13
- import {HelmTypes} from '@datagrok-libraries/js-draw-lite/src/types/org';
13
+ import {HelmType, HelmTypes, PolymerType, PolymerTypes} from '@datagrok-libraries/js-draw-lite/src/types/org';
14
+ import {polymerTypeToHelmType} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
14
15
 
15
16
  const Tags = new class {
16
17
  tooltipHandlerTemp = 'tooltip-handler.Monomer';
@@ -54,15 +55,17 @@ export class MonomerCellRendererBack extends CellRendererWithMonomerLibBackBase
54
55
  const biotype = alphabet === ALPHABET.RNA || alphabet === ALPHABET.DNA ? HelmTypes.NUCLEOTIDE : HelmTypes.AA;
55
56
  for (let i = 0; i < shortSymbols.length; i++) {
56
57
  const symbol: string = symbols[i];
58
+ const actBioType: HelmType = this.getHelmType(gridCell, biotype);
59
+
57
60
  let textcolor = undefinedColor;
58
61
  let backgroundcolor = 'rgb(255, 255, 255)';
59
62
  if (this.monomerLib) {
60
63
  if (applyToBackground) {
61
- const colors = this.monomerLib.getMonomerColors(biotype, symbol);
64
+ const colors = this.monomerLib.getMonomerColors(actBioType, symbol);
62
65
  textcolor = colors?.textcolor ?? textcolor;
63
66
  backgroundcolor = colors?.backgroundcolor ?? backgroundcolor;
64
67
  } else
65
- textcolor = this.monomerLib.getMonomerTextColor(biotype, symbol);
68
+ textcolor = this.monomerLib.getMonomerTextColor(actBioType, symbol);
66
69
  }
67
70
  if (applyToBackground && symbols.length == 1) {
68
71
  g.fillStyle = backgroundcolor;
@@ -101,7 +104,12 @@ export class MonomerCellRendererBack extends CellRendererWithMonomerLibBackBase
101
104
 
102
105
  const biotype = alphabet === ALPHABET.RNA || alphabet === ALPHABET.DNA ? HelmTypes.NUCLEOTIDE : HelmTypes.AA;
103
106
  const tooltipEls = monomerName.split(MONOMER_MOTIF_SPLITTER)
104
- .map((s) => !s || s === GAP_SYMBOL || s === DASH_GAP_SYMBOL ? ui.divText('gap') : this.monomerLib!.getTooltip(biotype, s));
107
+ .map((s) => {
108
+ if (!s || s === GAP_SYMBOL || s === DASH_GAP_SYMBOL)
109
+ return ui.divText('gap');
110
+ const actBioType: HelmType = this.getHelmType(gridCell, biotype);
111
+ return this.monomerLib!.getTooltip(actBioType, s);
112
+ });
105
113
  const tooltipEl = ui.divH(tooltipEls, {style: {alignItems: 'top'}});
106
114
  // tooltip max width is 600px, so we need to shrink the canvases a bit if needed. by default, it is 250px
107
115
  const canvases = Array.from(tooltipEl.querySelectorAll('canvas'));
@@ -117,6 +125,20 @@ export class MonomerCellRendererBack extends CellRendererWithMonomerLibBackBase
117
125
  return true; // To prevent default tooltip behaviour
118
126
  }
119
127
 
128
+ private getHelmType(gridCell: GridCell, defaultType: HelmType): HelmType {
129
+ let biotype = defaultType;
130
+ if ((gridCell.tableRowIndex ?? -1) > -1 && gridCell.tableColumn?.getTag(BioTags.polymerTypeColumnName)) {
131
+ const ptColName = gridCell.tableColumn.getTag(BioTags.polymerTypeColumnName);
132
+ const ptCol = gridCell.tableColumn.dataFrame?.col(ptColName);
133
+ if (ptCol) {
134
+ const ptrString = ptCol.get(gridCell.tableRowIndex!);
135
+ if (ptrString && [PolymerTypes.BLOB, PolymerTypes.CHEM, PolymerTypes.G, PolymerTypes.PEPTIDE, PolymerTypes.RNA].includes(ptrString))
136
+ biotype = polymerTypeToHelmType(ptrString as PolymerType);
137
+ }
138
+ }
139
+ return biotype;
140
+ }
141
+
120
142
  override async awaitRendered(timeout: number = 10000, reason: string = `${timeout} timeout`): Promise<void> {
121
143
  return Promise.resolve();
122
144
  }
@@ -162,5 +184,6 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
162
184
  onMouseMove(gridCell: GridCell, e: MouseEvent) {
163
185
  const back = MonomerCellRendererBack.getOrCreate(gridCell);
164
186
  back.onMouseMove(gridCell, e);
187
+ e.preventDefault();
165
188
  }
166
189
  }
@@ -304,7 +304,7 @@ export class MonomerLibBase implements IMonomerLibBase {
304
304
  }
305
305
 
306
306
  const naSymbol: string | undefined = monomer[OPT.NATURAL_ANALOG];
307
- if (!res && naSymbol)
307
+ if (!res && naSymbol && naSymbol !== monomer.symbol)
308
308
  return this.getMonomerColors(biotype, naSymbol);
309
309
  }
310
310