@datagrok/bio 2.27.4 → 2.27.6

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.27.4",
8
+ "version": "2.27.6",
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,7 +44,7 @@
44
44
  ],
45
45
  "dependencies": {
46
46
  "@biowasm/aioli": "^3.1.0",
47
- "@datagrok-libraries/bio": "^5.64.0",
47
+ "@datagrok-libraries/bio": "^5.64.1",
48
48
  "@datagrok-libraries/chem-meta": "^1.2.9",
49
49
  "@datagrok-libraries/math": "^1.2.6",
50
50
  "@datagrok-libraries/ml": "^6.10.11",
@@ -467,7 +467,7 @@ MWRSWY-CKHPMWRSWY-CKHP`;
467
467
  // collapse what used to be N distinct triple-tokens into a smaller union
468
468
  // of {sugar(s), bases, phosphate(s)} symbols.
469
469
  await _testDf(readSamples(Samples.testHelmCsv), {
470
- 'HELM string': new PosCol(NOTATION.HELM, null, null, 8, true),
470
+ 'HELM string': new PosCol(NOTATION.HELM, null, null, 7, true),
471
471
  }, seqHelper);
472
472
  });
473
473
 
@@ -25,6 +25,7 @@ category('projects', () => {
25
25
 
26
26
  async function saveAndOpenProject(tv: DG.TableView, dataSync?: boolean): Promise<void> {
27
27
  const project = DG.Project.create();
28
+ project.name = 'Test project';
28
29
  const tableInfo = tv.dataFrame.getTableInfo();
29
30
  if (dataSync) {
30
31
  //@ts-ignore
@@ -73,8 +73,8 @@ category('splitters', async () => {
73
73
  ['P', 'R', 'U', 'P', 'R', 'T'],
74
74
  ],
75
75
  testHelm3: [
76
- 'RNA1{P.R(U).P.R(T)}$$$$', // invalid helm, but oh well,
77
- ['P', 'R(U)', 'P', 'R', 'T'],
76
+ 'RNA1{P.R(U).P.R(T)}$$$$',
77
+ ['P', 'R', 'U', 'P', 'R', 'T'],
78
78
  ],
79
79
  };
80
80
 
@@ -167,11 +167,11 @@ export class MonomerLibBase implements IMonomerLibBase {
167
167
 
168
168
  /** Get or create {@link Monomer} object (in case it is missing in monomer library current config) */
169
169
  let m: Monomer | null = this.getMonomer(pt, elem);
170
- if (m && biotype == HelmTypes.LINKER && m[REQ.RGROUPS].length != 2) {
170
+ if (m && biotype == HelmTypes.LINKER && (m[REQ.RGROUPS]?.length ?? 0) < 2) {
171
171
  // Web Editor expects null
172
172
  return null;
173
173
  }
174
- if (m && biotype == HelmTypes.SUGAR && m[REQ.RGROUPS].length != 3) {
174
+ if (m && biotype == HelmTypes.SUGAR && (m[REQ.RGROUPS]?.length ?? 0) < 3) {
175
175
  // Web Editor expects null
176
176
  return null;
177
177
  }
@@ -491,7 +491,7 @@ export class MonomerManager implements IMonomerManager {
491
491
  ui.tooltip.bind(deleteButton, () =>
492
492
  `${(this.tv?.dataFrame?.selection?.trueCount ?? 0) > 0 ? 'Delete selected monomers' : 'Delete monomer'}`);
493
493
 
494
- const downloadButton = ui.iconFA('arrow-to-bottom', async () => {
494
+ const downloadAsJson = async () => {
495
495
  const libName = this.libInput.value;
496
496
  if (!libName)
497
497
  return grok.shell.error('No library selected');
@@ -508,6 +508,61 @@ export class MonomerManager implements IMonomerManager {
508
508
  if (!lib)
509
509
  return grok.shell.error(`Library ${libName} is empty`);
510
510
  DG.Utils.download(libName!, lib!, 'text/plain');
511
+ };
512
+
513
+ const downloadAsCsv = async () => {
514
+ const libName = this.libInput.value;
515
+ if (!libName)
516
+ return grok.shell.error('No library selected');
517
+ const df = this.tv?.dataFrame;
518
+ if (!df)
519
+ return grok.shell.error('No monomer table loaded');
520
+ const monomerCol = df.col(MONOMER_DF_COLUMN_NAMES.MONOMER);
521
+ const rgroupsCol = df.col(MONOMER_DF_COLUMN_NAMES.R_GROUPS);
522
+ if (!monomerCol || !rgroupsCol)
523
+ return grok.shell.error('Monomer or R-groups column not found');
524
+
525
+ const filtered = df.clone(df.filter);
526
+ const filteredMonomerCol = filtered.col(MONOMER_DF_COLUMN_NAMES.MONOMER)!;
527
+ const filteredRgroupsCol = filtered.col(MONOMER_DF_COLUMN_NAMES.R_GROUPS)!;
528
+ const cappedColName = filtered.columns.getUnusedName('Capped Molecule');
529
+ const cappedCol = filtered.columns.addNewString(cappedColName);
530
+ cappedCol.semType = DG.SEMTYPE.MOLECULE;
531
+
532
+ for (let i = 0; i < filtered.rowCount; i++) {
533
+ const smiles = filteredMonomerCol.get(i) as string | null;
534
+ if (!smiles) continue;
535
+ let rgroups: RGroup[] = [];
536
+ try {
537
+ const raw = filteredRgroupsCol.get(i) as string | null;
538
+ rgroups = raw ? JSON.parse(raw) : [];
539
+ } catch (_e) {
540
+ rgroups = [];
541
+ }
542
+ try {
543
+ cappedCol.set(i, capSmiles(smiles, rgroups), false);
544
+ } catch (e) {
545
+ console.error(`Error capping monomer at row ${i}`, e);
546
+ }
547
+ }
548
+
549
+ const orderedNames = filtered.columns.names();
550
+ const monomerIdx = orderedNames.indexOf(MONOMER_DF_COLUMN_NAMES.MONOMER);
551
+ if (monomerIdx >= 0) {
552
+ const reordered = orderedNames.filter((n) => n !== cappedColName);
553
+ reordered.splice(monomerIdx + 1, 0, cappedColName);
554
+ filtered.columns.setOrder(reordered);
555
+ }
556
+
557
+ const csvName = libName.toLowerCase().endsWith('.json') ? libName.replace(/\.json$/i, '.csv') : `${libName}.csv`;
558
+ DG.Utils.download(csvName, filtered.toCsv(), 'text/csv');
559
+ };
560
+
561
+ const downloadButton = ui.iconFA('arrow-to-bottom', () => {
562
+ DG.Menu.popup()
563
+ .item('JSON', () => { downloadAsJson(); })
564
+ .item('CSV', () => { downloadAsCsv(); })
565
+ .show();
511
566
  }, 'Download Monomer Library');
512
567
 
513
568
  ribbons.push([newMonomerButton, editButton, fixAllMonomersIcon, deleteButton, downloadButton]);