@datagrok/peptides 1.27.6 → 1.27.7

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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
3
  "friendlyName": "Peptides",
4
- "version": "1.27.6",
4
+ "version": "1.27.7",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -31,11 +31,11 @@
31
31
  "devDependencies": {
32
32
  "@datagrok-libraries/helm-web-editor": "^1.1.16",
33
33
  "@datagrok-libraries/js-draw-lite": "^0.0.5",
34
- "@datagrok/bio": "^2.24.0",
35
- "@datagrok/chem": "^1.13.0",
34
+ "@datagrok/bio": "^2.26.4",
35
+ "@datagrok/chem": "^1.17.1",
36
36
  "@datagrok/dendrogram": "^1.2.33",
37
37
  "@datagrok/eda": "^1.3.1",
38
- "@datagrok/helm": "^2.7.0",
38
+ "@datagrok/helm": "^2.13.0",
39
39
  "@types/uuid": "^10.0.0",
40
40
  "@types/wu": "^2.1.44",
41
41
  "@typescript-eslint/eslint-plugin": "^8.8.1",
@@ -42,6 +42,8 @@ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/types/monomer-lib
42
42
  import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
43
43
  import {PeptideUtils} from '../peptideUtils';
44
44
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
45
+ import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
46
+ import {getSeparator} from '../utils/misc';
45
47
 
46
48
  export enum SELECTION_MODE {
47
49
  MUTATION_CLIFFS = 'Mutation Cliffs',
@@ -543,6 +545,152 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
543
545
  throw new Error('Not implemented');
544
546
  }
545
547
 
548
+ /** Shows a dialog to choose extra columns, then exports all unique mutation cliffs as a new table view. */
549
+ exportMutationCliffs(): void {
550
+ if (!this.mutationCliffs) {
551
+ grok.shell.warning('Mutation cliffs have not been calculated yet.');
552
+ return;
553
+ }
554
+
555
+ const available = this.dataFrame.columns.toList()
556
+ .filter((col) => col.name !== this.activityColumnName && col.name !== this.sequenceColumnName &&
557
+ !this.positionColumns.some((pc) => pc.name === col.name))
558
+ .map((col) => col.name);
559
+
560
+ const columnsInput = ui.input.columns('Extra columns', {table: this.dataFrame, value: [], available, nullable: true});
561
+
562
+ ui.dialog('Export Mutation Cliffs')
563
+ .add(columnsInput.root)
564
+ .onOK(() => this._doExportMutationCliffs(columnsInput.value ?? []))
565
+ .show();
566
+ }
567
+
568
+ private _doExportMutationCliffs(extraColumns: DG.Column[]): void {
569
+ const mc = this.mutationCliffs!;
570
+ const alignedSeqCol = this.dataFrame.getCol(this.sequenceColumnName);
571
+ const alignedSeqColCategories = alignedSeqCol.categories;
572
+ const alignedSeqColData = alignedSeqCol.getRawData();
573
+ const activityCol = this.dataFrame.getCol(this.activityColumnName);
574
+ const activityColData = activityCol.getRawData();
575
+
576
+ const seq1Array: string[] = [];
577
+ const seq2Array: string[] = [];
578
+ const diffArray: string[] = [];
579
+ const act1Array: (number | null)[] = [];
580
+ const act2Array: (number | null)[] = [];
581
+ const deltaArray: (number | null)[] = [];
582
+ const extraData1: any[][] = extraColumns.map(() => []);
583
+ const extraData2: any[][] = extraColumns.map(() => []);
584
+
585
+ const seenPairs = new Set<string>();
586
+
587
+ for (const [_monomer, posMap] of mc.entries()) {
588
+ for (const [_position, indexMap] of posMap.entries()) {
589
+ for (const [refIdx, subIndexes] of indexMap.entries()) {
590
+ for (const subIdx of subIndexes) {
591
+ const pairKey = refIdx < subIdx ? `${refIdx}-${subIdx}` : `${subIdx}-${refIdx}`;
592
+ if (seenPairs.has(pairKey))
593
+ continue;
594
+ seenPairs.add(pairKey);
595
+
596
+ const seq1 = alignedSeqColCategories[alignedSeqColData[refIdx]];
597
+ const seq2 = alignedSeqColCategories[alignedSeqColData[subIdx]];
598
+ seq1Array.push(seq1);
599
+ seq2Array.push(seq2);
600
+ diffArray.push(`${seq1}#${seq2}`);
601
+
602
+ const a1 = activityCol.isNone(refIdx) ? null : activityColData[refIdx];
603
+ const a2 = activityCol.isNone(subIdx) ? null : activityColData[subIdx];
604
+ act1Array.push(a1);
605
+ act2Array.push(a2);
606
+ deltaArray.push(a1 == null || a2 == null ? null : a1 - a2);
607
+
608
+ for (let e = 0; e < extraColumns.length; e++) {
609
+ const eCol = extraColumns[e];
610
+ extraData1[e].push(eCol.isNone(refIdx) ? null : eCol.get(refIdx));
611
+ extraData2[e].push(eCol.isNone(subIdx) ? null : eCol.get(subIdx));
612
+ }
613
+ }
614
+ }
615
+ }
616
+ }
617
+
618
+ if (seq1Array.length === 0) {
619
+ grok.shell.warning('No mutation cliffs found to export.');
620
+ return;
621
+ }
622
+
623
+ const seq1Col = DG.Column.fromStrings('Seq 1', seq1Array);
624
+ const seq2Col = DG.Column.fromStrings('Seq 2', seq2Array);
625
+ const diffCol = DG.Column.fromStrings('Mutation', diffArray);
626
+
627
+ // Copy sequence tags (without notation provider) so the platform detects the same semtype
628
+ for (const col of [seq1Col, seq2Col]) {
629
+ for (const tag of alignedSeqCol.tags.keys()) {
630
+ if (tag !== '.notationProvider')
631
+ col.setTag(tag, alignedSeqCol.getTag(tag)!);
632
+ }
633
+ col.semType = alignedSeqCol.semType;
634
+ }
635
+
636
+ // Set up macromolecule difference column
637
+ diffCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
638
+ diffCol.setTag(C.TAGS.SEPARATOR, getSeparator(alignedSeqCol));
639
+ diffCol.setTag(DG.TAGS.UNITS, alignedSeqCol.getTag(DG.TAGS.UNITS) ?? '');
640
+ diffCol.setTag(DG.TAGS.CELL_RENDERER, 'MacromoleculeDifference');
641
+ diffCol.temp[SeqTemps.notationProvider] = alignedSeqCol.temp[SeqTemps.notationProvider];
642
+
643
+ const act1Col = DG.Column.fromList(DG.COLUMN_TYPE.FLOAT, `Seq 1 ${this.activityColumnName}`, act1Array);
644
+ const act2Col = DG.Column.fromList(DG.COLUMN_TYPE.FLOAT, `Seq 2 ${this.activityColumnName}`, act2Array);
645
+ const deltaCol = DG.Column.fromList(DG.COLUMN_TYPE.FLOAT, 'Delta', deltaArray);
646
+
647
+ const columns: DG.Column[] = [seq1Col, seq2Col, diffCol, act1Col, act2Col, deltaCol];
648
+
649
+ // Add extra columns (two per extra column: one for seq1, one for seq2)
650
+ for (let e = 0; e < extraColumns.length; e++) {
651
+ const eName = extraColumns[e].name;
652
+ const eType = extraColumns[e].type;
653
+ columns.push(DG.Column.fromList(eType as DG.COLUMN_TYPE, `Seq 1 ${eName}`, extraData1[e]));
654
+ columns.push(DG.Column.fromList(eType as DG.COLUMN_TYPE, `Seq 2 ${eName}`, extraData2[e]));
655
+ }
656
+
657
+ const df = DG.DataFrame.fromColumns(columns);
658
+ df.name = 'Mutation Cliffs';
659
+ grok.shell.addTableView(df);
660
+ }
661
+
662
+ /** Exports the invariant map as a new table view: monomer × position counts. */
663
+ exportInvariantMap(): void {
664
+ const stats = this.monomerPositionStats;
665
+ const uniqueMonomers = new Set<string>();
666
+ const positionNames: string[] = [];
667
+ for (const pos of Object.keys(stats)) {
668
+ if (pos === 'general')
669
+ continue;
670
+ positionNames.push(pos);
671
+ const posStats = stats[pos]!;
672
+ for (const monomer of Object.keys(posStats)) {
673
+ if (monomer === 'general')
674
+ continue;
675
+ uniqueMonomers.add(monomer);
676
+ }
677
+ }
678
+
679
+ const monomersArray = Array.from(uniqueMonomers).sort();
680
+ const monomerCol = DG.Column.fromStrings(C.COLUMNS_NAMES.MONOMER, monomersArray);
681
+ const columns: DG.Column[] = [monomerCol];
682
+
683
+ for (const pos of positionNames) {
684
+ const posStats = stats[pos]!;
685
+ const counts = monomersArray.map((m) => posStats[m]?.count ?? 0);
686
+ columns.push(DG.Column.fromList(DG.COLUMN_TYPE.INT, pos, counts));
687
+ }
688
+
689
+ const df = DG.DataFrame.fromColumns(columns);
690
+ df.name = 'Invariant Map';
691
+ grok.shell.addTableView(df);
692
+ }
693
+
546
694
  /** Removes all the active subscriptions. */
547
695
  detach(): void {
548
696
  this.subs.forEach((sub) => sub.unsubscribe());
@@ -567,6 +715,9 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
567
715
  if (!a || !a.causedBy || !a.args || !a.args.menu || !a.causedBy.target || !(a.causedBy.target instanceof HTMLElement) || !this.root.contains(a.causedBy.target))
568
716
  return;
569
717
  const menu = a.args.menu as DG.Menu;
718
+ const exportGroup = menu.group('Export');
719
+ exportGroup.item('Export Mutation Cliffs...', () => this.exportMutationCliffs());
720
+ exportGroup.item('Export Invariant Map', () => this.exportInvariantMap());
570
721
  getMonomerLibHelper().then((lh) => {
571
722
  const lib = lh.getMonomerLib();
572
723
  const mSymbols = lib.getMonomerSymbolsByType(PolymerTypes.PEPTIDE);