@datagrok/sequence-translator 1.1.0 → 1.1.4

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.
@@ -282,14 +282,14 @@ export class AxolabsTabUI {
282
282
  lstMy.push(ent);//getShortName(ent));
283
283
  }
284
284
 
285
- let loadPattern = ui.choiceInput('Load Pattern', '', lstMy, (v: string) => parsePatternAndUpdateUi(v));
285
+ let loadPattern = ui.choiceInput('Load pattern', '', lstMy, (v: string) => parsePatternAndUpdateUi(v));
286
286
 
287
287
  const currentUserName = (await grok.dapi.users.current()).friendlyName;
288
288
  const otherUsers = 'Other users';
289
289
 
290
290
  const patternListChoiceInput = ui.choiceInput('', currentUserName, [currentUserName, otherUsers], (v: string) => {
291
291
  const currentList = v === currentUserName ? lstMy : lstOthers;
292
- loadPattern = ui.choiceInput('Load Pattern', '', currentList, (v: string) => parsePatternAndUpdateUi(v));
292
+ loadPattern = ui.choiceInput('Load pattern', '', currentList, (v: string) => parsePatternAndUpdateUi(v));
293
293
 
294
294
  loadPattern.root.append(patternListChoiceInput.input);
295
295
  loadPattern.root.append(loadPattern.input);
@@ -391,7 +391,7 @@ export class AxolabsTabUI {
391
391
  const baseChoices: string[] = Object.keys(axolabsStyleMap);
392
392
  const defaultBase: string = baseChoices[0];
393
393
  const enumerateModifications = [defaultBase];
394
- const sequenceBase = ui.choiceInput('Sequence Basis', defaultBase, baseChoices, (v: string) => {
394
+ const sequenceBase = ui.choiceInput('Sequence basis', defaultBase, baseChoices, (v: string) => {
395
395
  updateBases(v);
396
396
  updateOutputExamples();
397
397
  });
@@ -421,7 +421,7 @@ export class AxolabsTabUI {
421
421
  ));
422
422
  const strandLengthInput = Object.fromEntries(STRANDS.map(
423
423
  (strand) => {
424
- const input = ui.intInput(`${strand} Length`, DEFAULT_SEQUENCE_LENGTH, () => updateUiForNewSequenceLength());
424
+ const input = ui.intInput(`${STRAND_NAME[strand]} length`, DEFAULT_SEQUENCE_LENGTH, () => updateUiForNewSequenceLength());
425
425
  input.setTooltip(`Length of ${STRAND_NAME[strand].toLowerCase()}, including overhangs`);
426
426
  return [strand, input];
427
427
  }));
@@ -437,7 +437,7 @@ export class AxolabsTabUI {
437
437
 
438
438
  // todo: rename to strandColumnInput
439
439
  const inputStrandColumn = Object.fromEntries(STRANDS.map((strand) => {
440
- const input: StringInput = ui.choiceInput(`${STRAND_NAME[strand]} Column`, '', [], (colName: string) => {
440
+ const input: StringInput = ui.choiceInput(`${STRAND_NAME[strand]} column`, '', [], (colName: string) => {
441
441
  validateStrandColumn(colName, strand);
442
442
  strandVar[strand] = colName;
443
443
  });
@@ -491,19 +491,21 @@ export class AxolabsTabUI {
491
491
  // todo: remove ts-ignore
492
492
  // @ts-ignore
493
493
  outputExample[s].input.disabled = 'true';
494
+ let options = ui.div([
495
+ ui.button(ui.iconFA('copy', () => {}), () => {
496
+ navigator.clipboard.writeText(outputExample[s].value).then(() =>
497
+ grok.shell.info('Sequence was copied to clipboard'));
498
+ }),
499
+ ], 'ui-input-options');
500
+ options.style.height = 'inherit';
494
501
  outputExample[s].root.append(
495
- ui.div([
496
- ui.button(ui.iconFA('copy', () => {}), () => {
497
- navigator.clipboard.writeText(outputExample[s].value).then(() =>
498
- grok.shell.info('Sequence was copied to clipboard'));
499
- }),
500
- ], 'ui-input-options'),
502
+ options
501
503
  );
502
504
  })
503
505
 
504
506
  const inputIdColumnDiv = ui.div([]);
505
507
  const svgDiv = ui.div([]);
506
- const asExampleDiv = ui.div([]);
508
+ const asExampleDiv = ui.div([], 'ui-form ui-form-wide');
507
509
  const appAxolabsDescription = ui.div([]);
508
510
  const loadPatternDiv = ui.div([]);
509
511
  const asModificationDiv = ui.div([]);
@@ -526,7 +528,7 @@ export class AxolabsTabUI {
526
528
 
527
529
  const tables = ui.tableInput('Tables', grok.shell.tables[0], grok.shell.tables, (t: DG.DataFrame) => {
528
530
  STRANDS.forEach((strand) => {
529
- inputStrandColumn[strand] = ui.choiceInput(`${strand} Column`, '', t.columns.names(), (colName: string) => {
531
+ inputStrandColumn[strand] = ui.choiceInput(`${strand} column`, '', t.columns.names(), (colName: string) => {
530
532
  validateStrandColumn(colName, strand);
531
533
  strandVar[strand] = colName;
532
534
  });
@@ -535,7 +537,7 @@ export class AxolabsTabUI {
535
537
  })
536
538
 
537
539
  // todo: unify with inputStrandColumn
538
- const inputIdColumn = ui.choiceInput('ID Column', '', t.columns.names(), (colName: string) => {
540
+ const inputIdColumn = ui.choiceInput('ID column', '', t.columns.names(), (colName: string) => {
539
541
  validateIdsColumn(colName);
540
542
  idVar = colName;
541
543
  });
@@ -546,7 +548,7 @@ export class AxolabsTabUI {
546
548
 
547
549
  // todo: unify with strandVar
548
550
  let idVar = '';
549
- const inputIdColumn = ui.choiceInput('ID Column', '', [], (colName: string) => {
551
+ const inputIdColumn = ui.choiceInput('ID column', '', [], (colName: string) => {
550
552
  validateIdsColumn(colName);
551
553
  idVar = colName;
552
554
  });
@@ -554,7 +556,7 @@ export class AxolabsTabUI {
554
556
 
555
557
  updatePatternsList();
556
558
 
557
- const createAsStrand = ui.boolInput('Create AS Strand', true, (v: boolean) => {
559
+ const createAsStrand = ui.boolInput('Anti sense strand', true, (v: boolean) => {
558
560
  modificationSection[AS].hidden = !v;
559
561
  inputStrandColumnDiv[AS].hidden = !v;
560
562
  asLengthDiv.hidden = !v;
@@ -565,7 +567,7 @@ export class AxolabsTabUI {
565
567
  });
566
568
  createAsStrand.setTooltip('Create antisense strand sections on SVG and table to the right');
567
569
 
568
- const saveAs = ui.textInput('Save As', 'Pattern Name', () => updateSvgScheme());
570
+ const saveAs = ui.textInput('Save as', 'Pattern name', () => updateSvgScheme());
569
571
  saveAs.setTooltip('Name Of New Pattern');
570
572
 
571
573
 
@@ -575,11 +577,11 @@ export class AxolabsTabUI {
575
577
 
576
578
  const comment = ui.textInput('Comment', '', () => updateSvgScheme());
577
579
 
578
- const savePatternButton = ui.button('Save', () => {
580
+ const savePatternButton = ui.bigButton('Save', () => {
579
581
  if (saveAs.value !== '')
580
582
  savePattern().then(() => grok.shell.info('Pattern saved'));
581
583
  else {
582
- const name = ui.stringInput('Enter Name', '');
584
+ const name = ui.stringInput('Enter name', '');
583
585
  ui.dialog('Pattern Name')
584
586
  .add(name.root)
585
587
  .onOK(() => {
@@ -590,7 +592,7 @@ export class AxolabsTabUI {
590
592
  }
591
593
  });
592
594
 
593
- const convertSequenceButton = ui.button('Convert Sequences', () => {
595
+ const convertSequenceButton = ui.bigButton('Convert', () => {
594
596
  const condition = [true, createAsStrand.value];
595
597
  if (STRANDS.some((s, i) => condition[i] && strandVar[s] === ''))
596
598
  grok.shell.info('Please select table and columns on which to apply pattern');
@@ -633,22 +635,19 @@ export class AxolabsTabUI {
633
635
  inputExample[SS].root,
634
636
  outputExample[SS].root,
635
637
  asExampleDiv,
636
- ], 'ui-form');
638
+ ], 'ui-form ui-form-wide');
637
639
 
638
- const inputsSection = ui.div([
640
+ const inputsSection = ui.block50([
639
641
  ui.h1('Convert options'),
640
- ui.divH([
641
- tables.root,
642
- inputStrandColumnDiv[SS],
643
- ]),
644
- ui.divH([
645
- inputStrandColumnDiv[AS],
646
- inputIdColumnDiv,
647
- ]),
642
+ tables.root,
643
+ inputStrandColumnDiv[SS],
644
+ inputStrandColumnDiv[AS],
645
+ inputIdColumnDiv,
648
646
  ui.buttonsInput([
649
647
  convertSequenceButton,
650
648
  ]),
651
- ], 'ui-form');
649
+ ]);
650
+ inputsSection.classList.add('ui-form');
652
651
 
653
652
  const downloadButton = ui.button('Download', () => svg.saveSvgAsPng(document.getElementById('mySvg'), saveAs.value,
654
653
  {backgroundColor: 'white'}));
@@ -665,7 +664,7 @@ export class AxolabsTabUI {
665
664
  ui.h1('Pattern options'),
666
665
  ]),
667
666
  ui.divH([
668
- ui.div([
667
+ ui.block([
669
668
  strandLengthInput[SS].root,
670
669
  asLengthDiv,
671
670
  sequenceBase.root,
@@ -676,7 +675,7 @@ export class AxolabsTabUI {
676
675
  savePatternButton,
677
676
  ]),
678
677
  ], 'ui-form'),
679
- ui.div([
678
+ ui.block([
680
679
  createAsStrand.root,
681
680
  fullyPto.root,
682
681
  firstPto[SS].root,
@@ -685,7 +684,7 @@ export class AxolabsTabUI {
685
684
  terminalModification[SS][THREE_PRIME].root,
686
685
  asModificationDiv,
687
686
  ], 'ui-form'),
688
- ], 'ui-form'),
687
+ ]),
689
688
  ], 'ui-form'),
690
689
  inputsSection,
691
690
  exampleSection,
@@ -58,9 +58,9 @@ export class MainTabUI {
58
58
  const sequenceColoredInput = new ColoredTextInput(this.sequenceInputBase, highlightInvalidSubsequence);
59
59
 
60
60
  const downloadMolfileButton = ui.button(
61
- 'Get Molfile',
61
+ 'Get SDF',
62
62
  () => { this.saveMolfile(); },
63
- 'Save sequence as Molfile V3000');
63
+ 'Save structure as SDF');
64
64
 
65
65
  const copySmilesButton = ui.button(
66
66
  'Copy SMILES',
@@ -100,8 +100,8 @@ export class MainTabUI {
100
100
 
101
101
  private saveMolfile(): void {
102
102
  const result = (new SequenceToMolfileConverter(this.sequence, false,
103
- this.formatChoiceInput.value!)).convert();
104
- download(this.sequence + '.mol', encodeURIComponent(result));
103
+ this.formatChoiceInput.value!)).convert() + '\n$$$$';
104
+ download(this.sequence + '.sdf', encodeURIComponent(result));
105
105
  }
106
106
 
107
107
  private copySmiles(): void {
@@ -26,9 +26,10 @@ const STRANDS = ['ss', 'as', 'as2'] as const;
26
26
  export class SdfTabUI {
27
27
  constructor() {
28
28
  this.onInput = new rxjs.Subject<string>();
29
+ this.onInvalidInput = new rxjs.Subject<string>();
29
30
  this.inputBase = Object.fromEntries(
30
31
  STRANDS.map(
31
- (key) => [key, ui.textInput('', DEFAULT_AXOLABS_INPUT, () => { this.onInput.next(); })]
32
+ (key) => [key, ui.textInput('', '', () => { this.onInput.next(); })]
32
33
  )
33
34
  );
34
35
  this.useChiralInput = ui.boolInput('Use chiral', true);
@@ -43,9 +44,14 @@ export class SdfTabUI {
43
44
  DG.debounce<string>(this.onInput, 300).subscribe(async () => {
44
45
  await this.updateMoleculeImg();
45
46
  });
47
+
48
+ DG.debounce<string>(this.onInvalidInput, 1000).subscribe(async () => {
49
+ grok.shell.warning('Insert Sense strand');
50
+ });
46
51
  }
47
52
 
48
53
  private onInput: rxjs.Subject<string>;
54
+ private onInvalidInput: rxjs.Subject<string>;
49
55
  private useChiralInput: DG.InputBase<boolean | null>;
50
56
  private saveAllStrandsInput: DG.InputBase<boolean | null>;
51
57
  private inputBase: {[key: string]: DG.InputBase<string>};
@@ -90,15 +96,21 @@ export class SdfTabUI {
90
96
 
91
97
  const directionChoiceInput = Object.fromEntries(
92
98
  STRANDS.map(
93
- (key) => [key, ui.choiceInput(
94
- `${key.toUpperCase()} direction`, DIRECTION.STRAIGHT, [DIRECTION.STRAIGHT, DIRECTION.INVERSE]
95
- )]
99
+ (key, idx) => {
100
+ const selected = (idx === 0) ? DIRECTION.STRAIGHT : DIRECTION.INVERSE;
101
+ return [key, ui.choiceInput(
102
+ `${key.toUpperCase()} direction`, selected, [DIRECTION.STRAIGHT, DIRECTION.INVERSE]
103
+ )]
104
+ }
96
105
  )
97
106
  );
98
107
 
99
- STRANDS.forEach((strand) => {
108
+ STRANDS.forEach((strand, idx) => {
100
109
  directionChoiceInput[strand].onChanged(() => {
101
- this.directionInversion[strand] = directionChoiceInput[strand].value === DIRECTION.INVERSE;
110
+ let value = directionChoiceInput[strand].value === DIRECTION.INVERSE;
111
+ // warning: the next line is necessary until the legacy notion of direction used in the molfile generation gets fixed
112
+ if (idx > 0) { value = !value; }
113
+ this.directionInversion[strand] = value;
102
114
  this.onInput.next();
103
115
  });
104
116
  });
@@ -142,14 +154,22 @@ export class SdfTabUI {
142
154
 
143
155
  private getStrandData() {
144
156
  return Object.fromEntries(
145
- STRANDS.map((strand) => [strand, {
146
- strand: this.inputBase[strand].value.replace(/\s*/g, ''),
147
- invert: this.directionInversion[strand]
148
- }])
157
+ STRANDS.map((strand, idx) => {
158
+ let invert = this.directionInversion[strand];
159
+ return [strand, {
160
+ strand: this.inputBase[strand].value.replace(/\s*/g, ''),
161
+ invert: invert
162
+ }]
163
+ })
149
164
  );
150
165
  }
151
166
 
152
167
  private getMolfile(ss: StrandData, as: StrandData, as2: StrandData): string {
168
+ if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
169
+ this.onInvalidInput.next();
170
+ return '';
171
+ }
172
+
153
173
  return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!);
154
174
  }
155
175
 
package/src/view/view.ts CHANGED
@@ -85,9 +85,7 @@ class TabLayout {
85
85
  if (control.currentPane.name !== MAIN_TAB)
86
86
  this.urlRouter.searchParams.delete('seq');
87
87
  else {
88
- console.log('sequence:', this.mainTab.sequence);
89
88
  this.urlRouter.searchParams.set('seq', this.mainTab.sequence);
90
- console.log('searchParams:', Object.entries(this.urlRouter.searchParams));
91
89
  }
92
90
  this.urlRouter.updatePath(control);
93
91
  });
@@ -1,33 +0,0 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
- import * as grok from 'datagrok-api/grok';
3
- import * as ui from 'datagrok-api/ui';
4
- import * as DG from 'datagrok-api/dg';
5
-
6
- import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
7
- import {DEFAULT_FORMATS} from '../model/const';
8
- import {getJsonData} from '../model/data-loading-utils/json-loader';
9
- import {axolabsToSmiles} from './const';
10
- import {_package} from '../package';
11
- import {SequenceToMolfileConverter} from '../model/sequence-to-structure-utils/sequence-to-molfile';
12
-
13
- function getSmiles(strand: string, format: string): string {
14
- const molfile = (new SequenceToMolfileConverter(strand, false, format)).convert();
15
- return DG.chem.convert(molfile, DG.chem.Notation.MolBlock, DG.chem.Notation.Smiles);
16
- }
17
-
18
- const AXOLABS = DEFAULT_FORMATS.AXOLABS;
19
-
20
- category('Axolabs to smiles', () => {
21
- before(async () => {
22
- await getJsonData();
23
- await _package.initMonomerLib();
24
- });
25
-
26
- for (const strand of Object.keys(axolabsToSmiles)) {
27
- test(`${strand} to SMILES`, async () => {
28
- const expected = axolabsToSmiles[strand];
29
- const result = getSmiles(strand, AXOLABS);
30
- expect(result, expected);
31
- });
32
- }
33
- });