@datagrok/sequence-translator 1.9.10 → 1.9.12

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.
@@ -3,26 +3,71 @@
3
3
  "heterodimerCode": "$2",
4
4
  "linkRules": [
5
5
  {
6
+ "code": 2,
6
7
  "firstMonomers": [
8
+ "D"
9
+ ],
10
+ "secondMonomers": [
7
11
  "NH2"
8
12
  ],
13
+ "firstLinkingGroup": 3,
14
+ "secondLinkingGroup": 2
15
+ },
16
+ {
17
+ "code": 1,
18
+ "firstMonomers": [
19
+ "C",
20
+ "dC"
21
+ ],
9
22
  "secondMonomers": [
10
- "D"
23
+ "C",
24
+ "dC"
11
25
  ],
12
- "firstLinkingGroup": "2",
13
- "secondLinkingGroup": "3",
14
- "code": "2"
26
+ "firstLinkingGroup": 3,
27
+ "secondLinkingGroup": 3
15
28
  },
16
29
  {
30
+ "code": 10,
17
31
  "firstMonomers": [
18
- "C"
32
+ "C",
33
+ "D",
34
+ "E",
35
+ "K"
19
36
  ],
20
37
  "secondMonomers": [
21
- "C"
38
+ "C",
39
+ "D",
40
+ "E",
41
+ "K"
42
+ ],
43
+ "firstLinkingGroup": 3,
44
+ "secondLinkingGroup": 2
45
+ },
46
+ {
47
+ "code": 11,
48
+ "firstMonomers": [
49
+ "C",
50
+ "E",
51
+ "K"
22
52
  ],
23
- "firstLinkingGroup": "3",
24
- "secondLinkingGroup": "3",
25
- "code": "1"
53
+ "secondMonomers": [
54
+ "NH2"
55
+ ],
56
+ "firstLinkingGroup": 3,
57
+ "secondLinkingGroup": 2
58
+ },
59
+ {
60
+ "code": 1,
61
+ "firstMonomers": [
62
+ "C",
63
+ "dC"
64
+ ],
65
+ "secondMonomers": [
66
+ "THA",
67
+ "MG3"
68
+ ],
69
+ "firstLinkingGroup": 3,
70
+ "secondLinkingGroup": 3
26
71
  }
27
72
  ],
28
73
  "reactionRules": [
@@ -36,6 +81,50 @@
36
81
  ],
37
82
  "reaction": "[C:1]N=[N+]=[N-].[C:2]C#C>>[C:1]N1-N=NC=C1[C:2]",
38
83
  "name": "GGaz"
84
+ },
85
+ {
86
+ "code": 8,
87
+ "firstMonomers": [
88
+ "DRR1"
89
+ ],
90
+ "secondMonomers": [
91
+ "DRR2"
92
+ ],
93
+ "reaction": "C=C[C:1].C=C/C=C/[C:2]>>C1=CC([C:2])C([C:1])CC1",
94
+ "name": "DARR"
95
+ },
96
+ {
97
+ "code": 8,
98
+ "firstMonomers": [
99
+ "ODAR1"
100
+ ],
101
+ "secondMonomers": [
102
+ "ODAR2"
103
+ ],
104
+ "reaction": "C=CC(=O)[C:1].C=C[C:2]>>C1CC([C:1])OC([C:2])C1",
105
+ "name": "ODARR"
106
+ },
107
+ {
108
+ "code": 7,
109
+ "firstMonomers": [
110
+ "PHAR1"
111
+ ],
112
+ "secondMonomers": [
113
+ "PHAR2"
114
+ ],
115
+ "reaction": "C=C[C:1].C=C[C:2]>>C1CC([C:2])C1[C:1]",
116
+ "name": "PHAR_CIS"
117
+ },
118
+ {
119
+ "code": 6,
120
+ "firstMonomers": [
121
+ "PHAR1"
122
+ ],
123
+ "secondMonomers": [
124
+ "PHAR2"
125
+ ],
126
+ "reaction": "C=C[C:1].C=C[C:2]>>C1C([C:1])CC1[C:2]",
127
+ "name": "PHAR_TRANS"
39
128
  }
40
129
  ]
41
- }
130
+ }
@@ -7,3 +7,9 @@ n,seqs
7
7
  6,D(2)-T-G-H-F-Y-P-NH2(2)
8
8
  7,R-F-azG(4)-T-G-H-F-Y-P-aG(4)-meI
9
9
  8,R-F-aG(4)-T-G-H-F-Y-P-azG(4)-meI
10
+ 9,R-F-R-I-F-D-C(1)-T-G-H-F-Y-G-H-F-Y-G-H-F-Y-P-THA(1)-meI-G-T
11
+ 10,R-F-R-I-F-D-C(1)-T-G-H-F-Y-G-H-F-Y-G-H-F-Y-P-MG3(1)-meI-G-T
12
+ 11,R-F-DRR1(8)-T-G-H-F-Y-P-DRR2(8)-C-C
13
+ 12,R-F-ODAR1(8)-T-G-H-F-Y-P-ODAR2(8)-meI-R-P-NH2
14
+ 13,R-F-PHAR1(7)-T-G-H-F-Y-P-PHAR2(7)-meI-F-K-NH2
15
+ 14,R-F-PHAR1(6)-T-G-H-F-Y-P-PHAR2(6)-C-C
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.9.10",
4
+ "version": "1.9.12",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -22,7 +22,7 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.54.7",
25
+ "@datagrok-libraries/bio": "^5.54.8",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.8",
27
27
  "@datagrok-libraries/tutorials": "^1.6.1",
28
28
  "@datagrok-libraries/utils": "^4.6.3",
@@ -54,7 +54,7 @@
54
54
  "@typescript-eslint/eslint-plugin": "^7.2.0",
55
55
  "@typescript-eslint/parser": "^7.2.0",
56
56
  "css-loader": "^6.7.3",
57
- "datagrok-tools": "^4.14.47",
57
+ "datagrok-tools": "^4.14.48",
58
58
  "eslint": "^8.57.0",
59
59
  "eslint-config-google": "^0.14.0",
60
60
  "style-loader": "^3.3.1",
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as grok from 'datagrok-api/grok';
2
3
  import * as ui from 'datagrok-api/ui';
3
4
  import * as DG from 'datagrok-api/dg';
@@ -13,6 +14,7 @@ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-he
13
14
  import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
14
15
  import {getOverriddenLibrary} from './pt-synthetic';
15
16
  import {helmToMol} from './pt-atomic';
17
+ import {execMonomerHoverLinks} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
16
18
 
17
19
  class MonomerCard {
18
20
  root: HTMLElement = ui.divV([], {classes: 'monomer-card-rule-root'});
@@ -24,11 +26,12 @@ class MonomerCard {
24
26
  this.root.style.border = value ? '2px solid var(--green-2)' : '2px solid var(--grey-2)';
25
27
  }
26
28
 
27
- constructor(public monomer: Monomer | null) {}
29
+ constructor(public monomer: Monomer | null, public monomerSymbol: string) {}
28
30
 
29
31
  render() {
32
+ ui.empty(this.root);
33
+ this.root.appendChild(ui.h2(this.monomerSymbol, {style: {textAlign: 'center'}}));
30
34
  if (this.monomer) {
31
- ui.empty(this.root);
32
35
  const monomerMolSvg = this.monomer.smiles && grok.chem.checkSmiles(this.monomer.smiles) ?
33
36
  grok.chem.drawMolecule(this.monomer.smiles, 150, 120) :
34
37
  grok.chem.drawMolecule(this.monomer.molfile ?? '', 150, 120);
@@ -52,6 +55,9 @@ class MonomerCard {
52
55
  ui.tooltip.bind(monomerType, this.monomer.polymerType);
53
56
 
54
57
  ui.tooltip.bind(this.root, 'Select Monomer');
58
+ } else {
59
+ this.root.appendChild(ui.divV([`Monomer ${this.monomerSymbol} not found in libraries`],
60
+ {style: {textAlign: 'center', height: '100%'}}));
55
61
  }
56
62
  }
57
63
  }
@@ -59,7 +65,6 @@ class MonomerCard {
59
65
  export class RuleCards {
60
66
  root: HTMLElement = ui.divH([],
61
67
  {style: {
62
- alignItems: 'center',
63
68
  width: '100%',
64
69
  overflow: 'hidden',
65
70
  visibility: 'visible',
@@ -74,47 +79,53 @@ export class RuleCards {
74
79
 
75
80
  constructor(public firstMonomers: string[], public secondMonomers: string[],
76
81
  lib: IMonomerLib, public code: number, public rules: Rules) {
77
- if (firstMonomers.length > 0) {
78
- this.actionable = true;
79
- const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
80
- const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
81
- this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
82
- const galleries = ui.divV([monomerGalleryFirst, monomerGallerySecond, this.resulting]);
83
- this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
84
- this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
85
-
86
- this.cardsFirst.forEach((card) => {
87
- card.root.onclick = () => {
88
- this.cardsFirst.forEach((c) => c.selected = false);
89
- card.selected = true;
90
- this.firstCard = card;
91
- this.reset();
92
- //onMonomerSelected(card.monomer);
93
- };
94
- monomerGalleryFirst.appendChild(card.root);
95
- });
96
-
97
- this.cardsSecond.forEach((card) => {
98
- card.root.onclick = () => {
99
- this.cardsSecond.forEach((c) => c.selected = false);
100
- card.selected = true;
101
- this.secondCard = card;
102
- this.reset();
103
- //onMonomerSelected(card.monomer);
104
- };
105
- monomerGallerySecond.appendChild(card.root);
106
- });
107
-
108
- this.cardsFirst[0].selected = true;
109
- this.cardsSecond[0].selected = true;
110
- this.firstCard = this.cardsFirst[0];
111
- this.secondCard = this.cardsSecond[0];
112
- this.root.appendChild(galleries);
113
- } else {
114
- const es = ui.divV(['Rule is active for all monomers, no examples to show']);
115
- this.root.appendChild(es);
116
- this.actionable = false;
117
- }
82
+ const emptyFirst = !firstMonomers?.length;
83
+ const emptySecond = !secondMonomers?.length;
84
+ // if one of the lists is empty, it means that the rule is active for all monomers
85
+ if (emptyFirst)
86
+ this.firstMonomers = firstMonomers = ['C', 'D', 'E', 'F', 'G'];
87
+ if (emptySecond)
88
+ this.secondMonomers = secondMonomers = ['D', 'C', 'E', 'F', 'G'];
89
+ this.actionable = true;
90
+ const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
91
+ const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
92
+
93
+ this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
94
+ const headerFirst = ui.h2('First Monomer' + (!emptyFirst ? '' : ' (Applied to all monomers, example list shown)'),
95
+ {style: {width: '100%'}});
96
+ const headerSecond = ui.h2('Second Monomer' + (!emptySecond ? '' : ' (Applied to all monomers, example list shown)'),
97
+ {style: {width: '100%'}});
98
+ const galleries = ui.divV([headerFirst, monomerGalleryFirst, headerSecond, monomerGallerySecond, this.resulting]);
99
+ this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol), symbol));
100
+ this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol), symbol));
101
+
102
+ this.cardsFirst.forEach((card) => {
103
+ card.root.onclick = () => {
104
+ this.cardsFirst.forEach((c) => c.selected = false);
105
+ card.selected = true;
106
+ this.firstCard = card;
107
+ this.reset();
108
+ //onMonomerSelected(card.monomer);
109
+ };
110
+ monomerGalleryFirst.appendChild(card.root);
111
+ });
112
+
113
+ this.cardsSecond.forEach((card) => {
114
+ card.root.onclick = () => {
115
+ this.cardsSecond.forEach((c) => c.selected = false);
116
+ card.selected = true;
117
+ this.secondCard = card;
118
+ this.reset();
119
+ //onMonomerSelected(card.monomer);
120
+ };
121
+ monomerGallerySecond.appendChild(card.root);
122
+ });
123
+
124
+ this.cardsFirst[0].selected = true;
125
+ this.cardsSecond[0].selected = true;
126
+ this.firstCard = this.cardsFirst[0];
127
+ this.secondCard = this.cardsSecond[0];
128
+ this.root.appendChild(galleries);
118
129
  }
119
130
 
120
131
  async reset() {
@@ -122,6 +133,7 @@ export class RuleCards {
122
133
  const seqs: string[] = [
123
134
  `${this.firstCard.monomer?.symbol}(${this.code})-A-A-A-A-${this.secondCard.monomer?.symbol}(${this.code})`
124
135
  ];
136
+ 'PEPTIDE1{[NH2].A.A.A.A.D}$PEPTIDE1,PEPTIDE1,1:R2-6:R3$$$V2.0';
125
137
 
126
138
  const helmHelper = await getHelmHelper();
127
139
  const [helms, isLinear, positionMaps] = doPolyToolConvert(seqs, this.rules, helmHelper);
@@ -143,11 +155,28 @@ export class RuleCards {
143
155
 
144
156
  const mol = resMolCol.get(0);
145
157
  const monomerMolSvg = mol && grok.chem.checkSmiles(mol) ?
146
- grok.chem.drawMolecule(mol, 150, 120) :
147
- grok.chem.drawMolecule(mol ?? '', 150, 120);
158
+ grok.chem.drawMolecule(mol, 200, 200) :
159
+ grok.chem.drawMolecule(mol ?? '', 200, 200);
160
+
161
+ if (mol) {
162
+ monomerMolSvg.style.cursor = 'pointer';
163
+ monomerMolSvg.onclick = () => {
164
+ const width = window.innerWidth - 200;
165
+ const height = window.innerHeight - 200;
166
+ const bigMol = grok.chem.checkSmiles(mol) ?
167
+ grok.chem.drawMolecule(mol, width, height) :
168
+ grok.chem.drawMolecule(mol ?? '', width, height);
169
+ ui.dialog({title: 'Molecule'}).add(bigMol).showModal(true);
170
+ };
171
+ ui.tooltip.bind(monomerMolSvg, 'Click to expand');
172
+ }
173
+
174
+ const exampleDiv = ui.divV([
175
+ ui.h2('Example Result:'), ui.h2(seqs[0])
176
+ ], {style: {width: '200px'}});
148
177
 
149
178
  ui.empty(this.resulting);
150
- this.resulting.append(ui.divH([monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
179
+ this.resulting.append(ui.divH([exampleDiv, monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
151
180
  }
152
181
  }
153
182
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as DG from 'datagrok-api/dg';
2
3
  import * as grok from 'datagrok-api/grok';
3
4
  import * as ui from 'datagrok-api/ui';
@@ -6,7 +7,9 @@ import {RulesManager} from './rule-manager';
6
7
  import {RuleCards} from './pt-rule-cards';
7
8
  import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
9
  import {
9
- PackageFunctions} from '../../package';
10
+ PackageFunctions} from '../../package';
11
+ import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
12
+ import {ReactionEditorProps} from './rule-reaction-editor';
10
13
 
11
14
  export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
12
15
  export const RULES_STORAGE_NAME = 'Polytool';
@@ -63,6 +66,15 @@ export type RuleReaction = {
63
66
  name: string
64
67
  }
65
68
 
69
+ export type LinkRuleRowArgs = {
70
+ row?: number,
71
+ code: number,
72
+ firstMonomers: string,
73
+ secondMonomers: string,
74
+ firstLinkingGroup: number,
75
+ secondLinkingGroup: number
76
+ }
77
+
66
78
  export class Rules {
67
79
  homodimerCode: string | null;
68
80
  heterodimerCode: string | null;
@@ -95,39 +107,54 @@ export class Rules {
95
107
  this.reactionRules.push(rules[j]);
96
108
  }
97
109
 
98
- getLinkRulesDf(): DG.DataFrame {
110
+ getLinkRulesDf() {
99
111
  const length = this.linkRules.length;
100
112
  const codeCol = DG.Column.int(NAME_CODE, length);
101
113
  codeCol.setTag('friendlyName', 'Code');
102
114
  //ui.tooltip.bind(codeCol.root, 'Click to zoom');
103
115
  const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
116
+ firstMonomerCol.temp[MmcrTemps.fontSize] = 16;
104
117
  firstMonomerCol.setTag('friendlyName', 'First monomers');
105
118
  firstMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
106
119
  PackageFunctions.applyNotationProviderForCyclized(firstMonomerCol, ',');
107
120
 
108
121
  const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
109
122
  secondMonomerCol.setTag('friendlyName', 'Second monomers');
123
+ secondMonomerCol.temp[MmcrTemps.fontSize] = 16;
110
124
  secondMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
111
125
  PackageFunctions.applyNotationProviderForCyclized(secondMonomerCol, ',');
112
126
 
113
- const firstLinkingGroup = DG.Column.int(NAME_FIRST_LINK, length);
114
- firstLinkingGroup.setTag('friendlyName', 'First group');
115
- const secondLinkingGroup = DG.Column.int(NAME_SECOND_LINK, length);
116
- secondLinkingGroup.setTag('friendlyName', 'Second group');
127
+ const firstLinkingGroupCol = DG.Column.int(NAME_FIRST_LINK, length);
128
+ firstLinkingGroupCol.setTag('friendlyName', 'First group');
129
+ const secondLinkingGroupCol = DG.Column.int(NAME_SECOND_LINK, length);
130
+ secondLinkingGroupCol.setTag('friendlyName', 'Second group');
117
131
 
118
132
  for (let i = 0; i < length; i++) {
119
133
  codeCol.set(i, this.linkRules[i].code);
120
134
  firstMonomerCol.set(i, this.linkRules[i].firstMonomers.toString());
121
135
  secondMonomerCol.set(i, this.linkRules[i].secondMonomers.toString());
122
- firstLinkingGroup.set(i, this.linkRules[i].firstLinkingGroup);
123
- secondLinkingGroup.set(i, this.linkRules[i].secondLinkingGroup);
136
+ firstLinkingGroupCol.set(i, this.linkRules[i].firstLinkingGroup);
137
+ secondLinkingGroupCol.set(i, this.linkRules[i].secondLinkingGroup);
124
138
  }
125
139
 
126
140
  const res = DG.DataFrame.fromColumns([
127
- codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroup, secondLinkingGroup
141
+ codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroupCol, secondLinkingGroupCol
128
142
  ]);
129
143
 
130
- return res;
144
+ const addNewRow = (rowObj: LinkRuleRowArgs) => {
145
+ if (rowObj.row != undefined && rowObj.row < res.rowCount && rowObj.row >= 0) {
146
+ codeCol.set(rowObj.row, rowObj.code);
147
+ firstMonomerCol.set(rowObj.row, rowObj.firstMonomers);
148
+ secondMonomerCol.set(rowObj.row, rowObj.secondMonomers);
149
+ firstLinkingGroupCol.set(rowObj.row, rowObj.firstLinkingGroup);
150
+ secondLinkingGroupCol.set(rowObj.row, rowObj.secondLinkingGroup);
151
+ } else {
152
+ const {code, firstMonomers, secondMonomers, firstLinkingGroup, secondLinkingGroup} = rowObj;
153
+ res.rows.addNew([code, firstMonomers ?? '', secondMonomers ?? '', firstLinkingGroup ?? 1, secondLinkingGroup ?? 2]);
154
+ }
155
+ };
156
+
157
+ return {res, addNewRow};
131
158
  }
132
159
 
133
160
  async getLinkCards(): Promise<RuleCards[]> {
@@ -144,7 +171,7 @@ export class Rules {
144
171
  return cards;
145
172
  }
146
173
 
147
- getSynthesisRulesDf(): DG.DataFrame {
174
+ getSynthesisRulesDf() {
148
175
  const length = this.reactionRules.length;
149
176
  const codeCol = DG.Column.int(NAME_CODE, length);
150
177
  codeCol.setTag('friendlyName', 'Code');
@@ -152,6 +179,15 @@ export class Rules {
152
179
  firstMonomerCol.setTag('friendlyName', 'First monomers');
153
180
  const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
154
181
  secondMonomerCol.setTag('friendlyName', 'Second monomers');
182
+ // set these columns as macromolecule for better visualization
183
+ firstMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
184
+ firstMonomerCol.temp[MmcrTemps.fontSize] = 16;
185
+ PackageFunctions.applyNotationProviderForCyclized(firstMonomerCol, ',');
186
+ secondMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
187
+ secondMonomerCol.temp[MmcrTemps.fontSize] = 16;
188
+ PackageFunctions.applyNotationProviderForCyclized(secondMonomerCol, ',');
189
+ secondMonomerCol.setTag(DG.TAGS.CELL_RENDERER, 'Sequence');
190
+ firstMonomerCol.setTag(DG.TAGS.CELL_RENDERER, 'Sequence');
155
191
  const name = DG.Column.string(NAME_REACTION_NAME, length);
156
192
  name.setTag('friendlyName', 'Name');
157
193
  const firstReactant = DG.Column.string('firstReactant', length);
@@ -179,9 +215,27 @@ export class Rules {
179
215
  product.semType = DG.SEMTYPE.MOLECULE;
180
216
 
181
217
 
182
- return DG.DataFrame.fromColumns([
218
+ const df = DG.DataFrame.fromColumns([
183
219
  name, firstReactant, secondReactant, product, codeCol, firstMonomerCol, secondMonomerCol
184
220
  ]);
221
+
222
+ const addNewRow = (rowObj: ReactionEditorProps) => {
223
+ if (rowObj.rowIndex != undefined && rowObj.rowIndex < df.rowCount && rowObj.rowIndex >= 0) {
224
+ name.set(rowObj.rowIndex, rowObj.resultMonomerName);
225
+ codeCol.set(rowObj.rowIndex, rowObj.code);
226
+ firstMonomerCol.set(rowObj.rowIndex, rowObj.firstMonomers.join(','));
227
+ secondMonomerCol.set(rowObj.rowIndex, rowObj.secondMonomers.join(','));
228
+ firstReactant.set(rowObj.rowIndex, rowObj.firstReactantSmiles);
229
+ secondReactant.set(rowObj.rowIndex, rowObj.secondReactantSmiles);
230
+ product.set(rowObj.rowIndex, rowObj.productSmiles);
231
+ } else {
232
+ const {resultMonomerName, code, firstMonomers, secondMonomers,
233
+ firstReactantSmiles, secondReactantSmiles, productSmiles} = rowObj;
234
+ df.rows.addNew([resultMonomerName, firstReactantSmiles, secondReactantSmiles,
235
+ productSmiles, code, firstMonomers.join(','), secondMonomers.join(',')]);
236
+ }
237
+ };
238
+ return {df, addNewRow};
185
239
  }
186
240
 
187
241
  setLinkRules(df: DG.DataFrame) : void {