@datagrok/bio 2.0.20 → 2.0.22

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": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.0.20",
8
+ "version": "2.0.22",
9
9
  "description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform",
10
10
  "repository": {
11
11
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@biowasm/aioli": "^3.1.0",
17
- "@datagrok-libraries/bio": "^5.1.0",
17
+ "@datagrok-libraries/bio": "^5.1.1",
18
18
  "@datagrok-libraries/chem-meta": "1.0.1",
19
19
  "@datagrok-libraries/ml": "^6.2.0",
20
20
  "@datagrok-libraries/utils": "^1.10.1",
package/src/package.ts CHANGED
@@ -99,7 +99,7 @@ export function checkInputColumn(
99
99
  ) {
100
100
  const notationAdd = allowedNotations.length == 0 ? 'any notation' :
101
101
  (`notation${allowedNotations.length > 1 ? 's' : ''} ${allowedNotations.map((n) => `"${n}"`).join(', ')} `);
102
- msg = `${name} + ' analysis is allowed for Macromolecules with notation ${notationAdd}.`;
102
+ msg = `${name} analysis is allowed for Macromolecules with ${notationAdd}.`;
103
103
  res = false;
104
104
  } else if (!uh.isHelm()) {
105
105
  // alphabet is not specified for 'helm' notation
@@ -521,7 +521,7 @@ export function saveAsFasta() {
521
521
  }
522
522
 
523
523
  //name: BioSubstructureFilter
524
- //description: Substructure filter for linear macromolecules
524
+ //description: Substructure filter for macromolecules
525
525
  //tags: filter
526
526
  //output: filter result
527
527
  //meta.semType: Macromolecule
@@ -78,7 +78,7 @@ export function linearSubstructureSearch(substructure: string, col: DG.Column):
78
78
  return resultArray;
79
79
  }
80
80
 
81
- async function helmSubstructureSearch(substructure: string, col: DG.Column): Promise<BitSet> {
81
+ export async function helmSubstructureSearch(substructure: string, col: DG.Column): Promise<BitSet> {
82
82
  const helmColWithSubstructure = DG.Column.string('helm', col.length + 1)
83
83
  .init((i) => i === col.length ? substructure : col.get(i));
84
84
  helmColWithSubstructure.setTag(DG.TAGS.UNITS, bio.NOTATION.HELM);
@@ -38,6 +38,7 @@ ATC-G-TTGC--
38
38
  seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
39
39
  seqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
40
40
  seqCol.setTag(bio.TAGS.alphabet, bio.ALPHABET.DNA);
41
+ seqCol.setTag(bio.TAGS.aligned, 'SEQ.MSA');
41
42
 
42
43
  const wlViewer: bio.WebLogo = (await df.plot.fromType('WebLogo')) as bio.WebLogo;
43
44
  tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN);
@@ -74,12 +75,12 @@ ATC-G-TTGC--
74
75
 
75
76
  test('positions with shrinkEmptyTail option true (filterd)', async () => {
76
77
  let csvDf2 = `seq
77
- -TC-G-TTGC--
78
- -TC-GCTTGC--
79
- -T--C-GT-
80
- -T--C-GT-
81
- -T--C-GT-
82
- -T--CCGT-`;
78
+ -TC-G-TTGC--
79
+ -TC-GCTTGC--
80
+ -T--C-GT-
81
+ -T--C-GT-
82
+ -T--C-GT-
83
+ -T--CCGT-`;
83
84
  const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf2);
84
85
  const tv: DG.TableView = grok.shell.addTableView(df);
85
86
 
@@ -87,6 +88,7 @@ ATC-G-TTGC--
87
88
  seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
88
89
  seqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
89
90
  seqCol.setTag(bio.TAGS.alphabet, bio.ALPHABET.DNA);
91
+ seqCol.setTag(bio.TAGS.aligned, 'SEQ');
90
92
 
91
93
  df.filter.init((i) => {
92
94
  return i > 2;
@@ -131,6 +133,7 @@ ATC-G-TTGC--
131
133
  seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
132
134
  seqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
133
135
  seqCol.setTag(bio.TAGS.alphabet, bio.ALPHABET.DNA);
136
+ seqCol.setTag(bio.TAGS.aligned, 'SEQ.MSA');
134
137
 
135
138
  const wlViewer: bio.WebLogo = (await df.plot.fromType('WebLogo',
136
139
  {'skipEmptyPositions': true})) as bio.WebLogo;
@@ -27,11 +27,13 @@ seq4`;
27
27
  const df: DG.DataFrame = DG.DataFrame.fromCsv(csv);
28
28
  const col: DG.Column = df.getCol('seq');
29
29
  col.semType = DG.SEMTYPE.MACROMOLECULE;
30
- col.setTag(DG.TAGS.UNITS, 'fasta');
30
+ col.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
31
31
  col.setTag(bio.TAGS.alphabet, bio.ALPHABET.DNA);
32
+ col.setTag(bio.TAGS.aligned, 'SEQ');
32
33
 
33
34
  const [res, msg]: [boolean, string] = checkInputColumn(
34
- col, 'Test', ['fasta',], ['DNA', 'RNA', 'PT']);
35
+ col, 'Test', [bio.NOTATION.FASTA,],
36
+ [bio.ALPHABET.DNA, bio.ALPHABET.RNA, bio.ALPHABET.PT]);
35
37
 
36
38
  expect(res, true);
37
39
  });
@@ -45,7 +47,8 @@ seq4`;
45
47
  col.setTag(bio.TAGS.alphabetIsMultichar, 'true');
46
48
 
47
49
  const [res, msg]: [boolean, string] = checkInputColumn(
48
- col, 'Test', ['fasta',], ['DNA', 'RNA', 'PT']);
50
+ col, 'Test', [bio.NOTATION.FASTA,],
51
+ [bio.ALPHABET.DNA, bio.ALPHABET.RNA, bio.ALPHABET.PT]);
49
52
 
50
53
  expect(res, false);
51
54
  });
@@ -58,9 +61,11 @@ seq4`;
58
61
  col.setTag(bio.TAGS.alphabet, 'UN');
59
62
  col.setTag(bio.TAGS.alphabetSize, '11');
60
63
  col.setTag(bio.TAGS.alphabetIsMultichar, 'true');
64
+ col.setTag(bio.TAGS.aligned, 'SEQ');
61
65
 
62
66
  const [res, msg]: [boolean, string] = checkInputColumn(
63
- col, 'Test', ['fasta',], ['DNA', 'RNA', 'PT']);
67
+ col, 'Test', [bio.NOTATION.FASTA,],
68
+ [bio.ALPHABET.DNA, bio.ALPHABET.RNA, bio.ALPHABET.PT]);
64
69
 
65
70
  expect(res, false);
66
71
  });
@@ -6,18 +6,21 @@
6
6
 
7
7
  import * as ui from 'datagrok-api/ui';
8
8
  import * as DG from 'datagrok-api/dg';
9
- import * as bio from '@datagrok-libraries/bio';
10
9
 
10
+ import * as grok from 'datagrok-api/grok';
11
11
  import wu from 'wu';
12
- import {linearSubstructureSearch} from '../substructure-search/substructure-search';
12
+ import {helmSubstructureSearch, linearSubstructureSearch} from '../substructure-search/substructure-search';
13
13
  import {Subject, Subscription} from 'rxjs';
14
14
  import * as C from '../utils/constants';
15
+ import {updateDivInnerHTML} from '../utils/ui-utils';
16
+ import {NOTATION} from '@datagrok-libraries/bio';
15
17
 
16
18
  export class BioSubstructureFilter extends DG.Filter {
17
- bioFilter: FastaFilter | SeparatorFilter | null = null;
19
+ bioFilter: FastaFilter | SeparatorFilter | HelmFilter | null = null;
18
20
  bitset: DG.BitSet | null = null;
19
21
  loader: HTMLDivElement = ui.loader();
20
22
  onBioFilterChangedSubs?: Subscription;
23
+ notation: string | undefined = '';
21
24
 
22
25
  get calculating(): boolean { return this.loader.style.display == 'initial'; }
23
26
 
@@ -45,9 +48,10 @@ export class BioSubstructureFilter extends DG.Filter {
45
48
  super.attach(dataFrame);
46
49
  this.column = dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
47
50
  this.columnName = this.column?.name;
48
- const notation = this.column?.getTag(DG.TAGS.UNITS);
49
- this.bioFilter = notation === bio.NOTATION.FASTA ?
50
- new FastaFilter() : new SeparatorFilter(this.column!.getTag(C.TAGS.SEPARATOR));
51
+ this.notation = this.column?.getTag(DG.TAGS.UNITS);
52
+ this.bioFilter = this.notation === NOTATION.FASTA ?
53
+ new FastaFilter() : this.notation === NOTATION.SEPARATOR ?
54
+ new SeparatorFilter(this.column!.getTag(C.TAGS.SEPARATOR)) : new HelmFilter();
51
55
  this.root.appendChild(this.bioFilter!.filterPanel);
52
56
  this.root.appendChild(this.loader);
53
57
 
@@ -76,7 +80,7 @@ export class BioSubstructureFilter extends DG.Filter {
76
80
  applyState(state: any): void {
77
81
  super.applyState(state);
78
82
  if (state.bioSubstructure)
79
- this.bioFilter!.substructureInput.value = state.bioSubstructure;
83
+ this.bioFilter!.substructure = state.bioSubstructure;
80
84
 
81
85
  const that = this;
82
86
  if (state.bioSubstructure)
@@ -98,7 +102,9 @@ export class BioSubstructureFilter extends DG.Filter {
98
102
  } else {
99
103
  this.calculating = true;
100
104
  try {
101
- this.bitset = linearSubstructureSearch(this.bioFilter!.substructure, this.column!);
105
+ this.bitset = this.notation === NOTATION.HELM ?
106
+ await helmSubstructureSearch(this.bioFilter!.substructure, this.column!) :
107
+ linearSubstructureSearch(this.bioFilter!.substructure, this.column!);
102
108
  this.calculating = false;
103
109
  this.dataFrame?.rows.requestFilter();
104
110
  } finally {
@@ -108,13 +114,28 @@ export class BioSubstructureFilter extends DG.Filter {
108
114
  }
109
115
  }
110
116
 
111
- class FastaFilter {
117
+ abstract class BioFilterBase {
112
118
  onChanged: Subject<any> = new Subject<any>();
119
+
120
+ get filterPanel() {
121
+ return new HTMLElement();
122
+ }
123
+
124
+ get substructure() {
125
+ return '';
126
+ }
127
+
128
+ set substructure(s: string) {
129
+ }
130
+ }
131
+
132
+ class FastaFilter extends BioFilterBase {
113
133
  substructureInput: DG.InputBase<string> = ui.stringInput('', '', () => {
114
134
  this.onChanged.next();
115
135
  }, {placeholder: 'Substructure'});
116
136
 
117
137
  constructor() {
138
+ super();
118
139
  }
119
140
 
120
141
  get filterPanel() {
@@ -124,6 +145,10 @@ class FastaFilter {
124
145
  get substructure() {
125
146
  return this.substructureInput.value;
126
147
  }
148
+
149
+ set substructure(s: string) {
150
+ this.substructureInput.value = s;
151
+ }
127
152
  }
128
153
 
129
154
  class SeparatorFilter extends FastaFilter {
@@ -150,4 +175,54 @@ class SeparatorFilter extends FastaFilter {
150
175
  this.substructureInput.value.replaceAll(this.separatorInput.value, this.colSeparator) :
151
176
  this.substructureInput.value;
152
177
  }
178
+
179
+ set substructure(s: string) {
180
+ this.substructureInput.value = s;
181
+ }
182
+ }
183
+
184
+ class HelmFilter extends BioFilterBase {
185
+ helmEditor: any;
186
+ _filterPanel = ui.div('', {style: {width: '100px', height: '100px'}});
187
+ helmSubstructure = '';
188
+ editDiv = ui.divText('Click to edit', {style: {cursor: 'pointer'}});
189
+
190
+ constructor() {
191
+ super();
192
+ this.init();
193
+ ui.setUpdateIndicator(this._filterPanel, true);
194
+ }
195
+
196
+ async init() {
197
+ this.helmEditor = await grok.functions.call('HELM:helmWebEditor');
198
+ updateDivInnerHTML(this._filterPanel, this.editDiv);
199
+ ui.setUpdateIndicator(this._filterPanel, false);
200
+ this._filterPanel.addEventListener('click', (event: MouseEvent) => {
201
+ //@ts-ignore
202
+ ui.dialog({showHeader: false, showFooter: true})
203
+ .add(this.helmEditor.editorView)
204
+ .onOK(() => {
205
+ const helmString = this.helmEditor
206
+ .webEditor.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
207
+ if (helmString) {
208
+ updateDivInnerHTML(this._filterPanel, this.helmEditor.host);
209
+ this.helmEditor.editor.setHelm(helmString);
210
+ } else { updateDivInnerHTML(this._filterPanel, this.editDiv); }
211
+ this.helmSubstructure = helmString;
212
+ this.onChanged.next();
213
+ }).show({modal: true, fullScreen: true});
214
+ });
215
+ }
216
+
217
+ get filterPanel() {
218
+ return this._filterPanel;
219
+ }
220
+
221
+ get substructure() {
222
+ return this.helmSubstructure;
223
+ }
224
+
225
+ set substructure(s: string) {
226
+ this.helmEditor.editor.setHelm(s);
227
+ }
153
228
  }