@datagrok/bio 2.24.0 → 2.25.1

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/detectors.js +26 -12
  3. package/dist/455.js.map +1 -1
  4. package/dist/package-test.js +2 -2
  5. package/dist/package-test.js.map +1 -1
  6. package/dist/package.js +2 -2
  7. package/dist/package.js.map +1 -1
  8. package/files/samples/HELM_CHEMS.csv +11 -0
  9. package/package.json +2 -2
  10. package/src/analysis/sequence-space.ts +1 -1
  11. package/src/demo/bio03-atomic-level.ts +1 -1
  12. package/src/package-types.ts +1 -1
  13. package/src/package.ts +1 -1
  14. package/src/tests/monomer-libraries-tests.ts +1 -1
  15. package/src/utils/get-region.ts +2 -2
  16. package/src/utils/helm-to-molfile/converter/const.ts +0 -1
  17. package/src/utils/helm-to-molfile/converter/converter.ts +3 -3
  18. package/src/utils/helm-to-molfile/converter/helm.ts +14 -6
  19. package/src/utils/helm-to-molfile/converter/mol-bonds.ts +1 -1
  20. package/src/utils/helm-to-molfile/converter/mol-wrapper.ts +2 -2
  21. package/src/utils/helm-to-molfile/converter/r-group-handler.ts +2 -2
  22. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +1 -1
  23. package/src/utils/monomer-lib/library-file-manager/ui.ts +22 -5
  24. package/src/utils/monomer-lib/monomer-lib-base.ts +31 -3
  25. package/src/utils/monomer-lib/monomer-lib.ts +0 -26
  26. package/src/utils/monomer-lib/monomer-manager/monomer-manager.ts +1 -1
  27. package/src/utils/monomer-lib/smiles2Monomer.ts +128 -0
  28. package/src/utils/monomer-lib/web-editor-monomer-dummy.ts +15 -1
  29. package/src/utils/multiple-sequence-alignment-ui.ts +1 -1
  30. package/src/utils/multiple-sequence-alignment.ts +1 -1
  31. package/src/utils/seq-helper/seq-handler.ts +25 -16
  32. package/src/utils/ui-utils.ts +1 -1
  33. package/src/viewers/web-logo-viewer.ts +19 -8
  34. package/test-console-output-1.log +784 -775
  35. package/test-record-1.mp4 +0 -0
@@ -132,7 +132,7 @@ export class SeqHandler implements ISeqHandler {
132
132
  for (const seq of values) {
133
133
  const mSeq = !!seq ? splitter(seq) : [];
134
134
 
135
- if (firstLength === null)
135
+ if (firstLength == null)
136
136
  firstLength = mSeq.length;
137
137
  else if (mSeq.length !== firstLength)
138
138
  sameLength = false;
@@ -182,13 +182,13 @@ export class SeqHandler implements ISeqHandler {
182
182
  throw new Error('Alphabet is empty and not annotated.');
183
183
 
184
184
  let aligned = uh.column.getTag(TAGS.aligned);
185
- if (aligned === null) {
185
+ if (aligned == null) {
186
186
  aligned = uh.stats.sameLength ? ALIGNMENT.SEQ_MSA : ALIGNMENT.SEQ;
187
187
  uh.column.setTag(TAGS.aligned, aligned);
188
188
  }
189
189
 
190
190
  let alphabet = uh.column.getTag(TAGS.alphabet);
191
- if (alphabet === null) {
191
+ if (alphabet == null) {
192
192
  alphabet = detectAlphabet(uh.stats.freq, candidateAlphabets);
193
193
  uh.column.setTag(TAGS.alphabet, alphabet);
194
194
  }
@@ -200,7 +200,7 @@ export class SeqHandler implements ISeqHandler {
200
200
  }
201
201
  } else if (units === NOTATION.HELM) {
202
202
  let alphabet = uh.column.getTag(TAGS.alphabet);
203
- if (alphabet === null) {
203
+ if (alphabet == null) {
204
204
  // const cats = uh.column.categories;
205
205
  // const splitter = uh.getSplitter();
206
206
  // const samples = Array.from(new Set(
@@ -232,7 +232,7 @@ export class SeqHandler implements ISeqHandler {
232
232
 
233
233
  public get separator(): string | undefined {
234
234
  const separator: string | undefined = this.column.getTag(TAGS.separator) ?? undefined;
235
- if (this.notation === NOTATION.SEPARATOR && separator === undefined)
235
+ if (this.notation === NOTATION.SEPARATOR && separator == undefined)
236
236
  throw new Error(`Separator is mandatory for column '${this.column.name}' of notation '${this.notation}'.`);
237
237
  return separator;
238
238
  }
@@ -327,7 +327,7 @@ export class SeqHandler implements ISeqHandler {
327
327
  const seq = this.column.get(rowIdx);
328
328
  return this.getSplitter(limit)(seq);
329
329
  } else {
330
- if (this.column.version !== this.columnVersion || this._splitted === null) {
330
+ if (this.column.version !== this.columnVersion || this._splitted == null) {
331
331
  this.columnVersion = this.column.version;
332
332
  this._splitted = new Array<WeakRef<ISeqSplitted>>(this.column.length);
333
333
  }
@@ -408,7 +408,7 @@ export class SeqHandler implements ISeqHandler {
408
408
  }
409
409
 
410
410
  public get stats(): SeqColStats {
411
- if (this._stats === null) {
411
+ if (this._stats == null) {
412
412
  const freq: { [m: string]: number } = {};
413
413
  let sameLength = true;
414
414
  let firstLength = null;
@@ -435,7 +435,7 @@ export class SeqHandler implements ISeqHandler {
435
435
 
436
436
  private _maxLength: number | null = null;
437
437
  public get maxLength(): number {
438
- if (this._maxLength === null) {
438
+ if (this._maxLength == null) {
439
439
  this._maxLength = this.column.length === 0 ? 0 :
440
440
  wu.count(0).take(this.column.length).map((rowIdx) => this.getSplitted(rowIdx).length).reduce((a, b) => a > b ? a : b, 0);
441
441
  }
@@ -444,7 +444,7 @@ export class SeqHandler implements ISeqHandler {
444
444
 
445
445
  private _posList: string[] | null = null;
446
446
  public get posList(): string[] {
447
- if (this._posList === null) {
447
+ if (this._posList == null) {
448
448
  const posListTxt = this.column.getTag(TAGS.positionNames);
449
449
  this._posList = posListTxt ? posListTxt.split(positionSeparator).map((p) => p.trim()) :
450
450
  wu.count(1).take(this.maxLength).map((pos) => pos.toString()).toArray();
@@ -619,7 +619,7 @@ export class SeqHandler implements ISeqHandler {
619
619
  }
620
620
 
621
621
  get splitter(): SplitterFunc {
622
- if (this._splitter === null)
622
+ if (this._splitter == null)
623
623
  this._splitter = this.getSplitter();
624
624
  return this._splitter;
625
625
  }
@@ -1049,21 +1049,30 @@ function joinToHelm(srcSS: ISeqSplitted, wrappers: string[], isDnaOrRna: boolean
1049
1049
  }
1050
1050
 
1051
1051
  function joinToBiln(srcSS: ISeqSplitted): string {
1052
+ const needsSquareBrackets = (cm: string | null) => {
1053
+ return cm && (cm.includes('-') || cm.includes('*') || cm.includes('[R'));
1054
+ };
1055
+
1052
1056
  if (!srcSS.graphInfo || !((srcSS.graphInfo.connections?.length ?? 0) > 0)) {
1053
1057
  const resOMList: string[] = new Array<string>(srcSS.length);
1054
1058
  for (let posIdx: number = 0; posIdx < srcSS.length; ++posIdx) {
1055
- resOMList[posIdx] = srcSS.getCanonical(posIdx);
1056
- if (resOMList[posIdx]?.includes('-')) // Biln uses '-' as a separator, need to enclose in []
1057
- resOMList[posIdx] = `[${resOMList[posIdx]}]`;
1059
+ const canonical = srcSS.getCanonical(posIdx);
1060
+ if (needsSquareBrackets(canonical)) // Biln uses '-' as a separator, need to enclose in []. also there might be smiles in there, where Rs are represented as '*' or R
1061
+ resOMList[posIdx] = `[${canonical}]`;
1062
+ else
1063
+ resOMList[posIdx] = canonical;
1058
1064
  }
1059
1065
  return resOMList.join('-'); // Biln uses '-' as a separator
1060
1066
  } else { // conversion happens only if there is a graph info
1061
1067
  const disjointSequenceIdxs = srcSS.graphInfo.disjointSeqStarts;
1062
1068
  const allSeqParts = new Array<string>(srcSS.length);
1063
1069
  for (let posIdx = 0; posIdx < srcSS.length; ++posIdx) {
1064
- allSeqParts[posIdx] = srcSS.getCanonical(posIdx);
1065
- if (allSeqParts[posIdx]?.includes('-')) // Biln uses '-' as a separator, need to enclose in []
1066
- allSeqParts[posIdx] = `[${allSeqParts[posIdx]}]`;
1070
+ const canonical = srcSS.getCanonical(posIdx);
1071
+ // allSeqParts[posIdx] = srcSS.getCanonical(posIdx);
1072
+ if (needsSquareBrackets(canonical)) // Biln uses '-' as a separator, need to enclose in []
1073
+ allSeqParts[posIdx] = `[${canonical}]`;
1074
+ else
1075
+ allSeqParts[posIdx] = canonical;
1067
1076
  }
1068
1077
  for (let i = 0; i < srcSS.graphInfo.connections.length; i++) {
1069
1078
  const conn: ISeqConnection = srcSS.graphInfo.connections[i];
@@ -3,7 +3,7 @@ import * as DG from 'datagrok-api/dg';
3
3
 
4
4
  export function getMacromoleculeColumns(): DG.Column<string>[] {
5
5
  const columns = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
6
- if (columns === null) {
6
+ if (columns == null) {
7
7
  grok.shell.error('Current table does not contain macromolecules');
8
8
  return [];
9
9
  }
@@ -34,6 +34,7 @@ import {AggFunc, getAgg} from '../utils/agg';
34
34
  import {_package, PackageFunctions} from '../package';
35
35
  import {numbersWithinMaxDiff} from './utils';
36
36
  import {buildCompositionTable} from '@datagrok-libraries/bio/src/utils/composition-table';
37
+ import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
37
38
 
38
39
  declare global {
39
40
  interface HTMLCanvasElement {
@@ -212,14 +213,24 @@ export class PositionInfo {
212
213
  ) {
213
214
  for (const [monomer, pmInfo] of Object.entries(this._freqs)) {
214
215
  if (monomer !== GAP_SYMBOL) {
215
- const monomerTxt = monomerToShort(monomer, maxMonomerLetters);
216
+ // to handle explicit smiles based monomers in monomer lib
217
+ let monomerDisplayValue = monomer;
218
+
216
219
  const b = pmInfo.bounds!;
217
220
  const left = b.left;
218
221
 
219
222
  let color: string = undefinedColor;
220
- if (monomerLib)
221
- color = monomerLib.getMonomerTextColor(biotype, monomer)!;
222
-
223
+ if (monomerLib) {
224
+ try {
225
+ color = monomerLib.getMonomerTextColor(biotype, monomer)!;
226
+ const m = monomerLib.getMonomer(helmTypeToPolymerType(biotype), monomer);
227
+ if (m && m.symbol !== monomer) // for explicit smiles based monomers
228
+ monomerDisplayValue = m.symbol;
229
+ } catch (e) {
230
+ errorToConsole(e);
231
+ }
232
+ }
233
+ const monomerTxt = monomerToShort(monomerDisplayValue, maxMonomerLetters);
223
234
  g.resetTransform();
224
235
  g.strokeStyle = 'lightgray';
225
236
  g.lineWidth = 1;
@@ -949,7 +960,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
949
960
  return [null, null, null];
950
961
 
951
962
  const monomer: string | undefined = pi.getMonomerAt(calculatedX, p.y);
952
- if (monomer === undefined)
963
+ if (monomer == undefined)
953
964
  return [pi, null, null];
954
965
 
955
966
  return [pi, monomer, pi.getFreq(monomer)];
@@ -1262,7 +1273,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
1262
1273
  const [pi, monomer] = this.getMonomer(cursorP, dpr);
1263
1274
  const positionLabelHeight = this.showPositionLabels ? POSITION_LABELS_HEIGHT * dpr : 0;
1264
1275
 
1265
- if (pi !== null && monomer === null && 0 <= cursorP.y && cursorP.y <= positionLabelHeight) {
1276
+ if (pi !== null && monomer == null && 0 <= cursorP.y && cursorP.y <= positionLabelHeight) {
1266
1277
  // Position tooltip
1267
1278
 
1268
1279
  const tooltipRows = [ui.divText(`Position ${pi.label}`)];
@@ -1373,8 +1384,8 @@ function renderPositionLabels(g: CanvasRenderingContext2D,
1373
1384
  const pos = positions[jPos];
1374
1385
  const tm = g.measureText(pos.name);
1375
1386
  const textHeight = tm.actualBoundingBoxDescent - tm.actualBoundingBoxAscent;
1376
- maxPosNameWidth = maxPosNameWidth === null ? tm.width : Math.max(maxPosNameWidth, tm.width);
1377
- maxPosNameHeight = maxPosNameHeight === null ? textHeight : Math.max(maxPosNameHeight, textHeight);
1387
+ maxPosNameWidth = maxPosNameWidth == null ? tm.width : Math.max(maxPosNameWidth, tm.width);
1388
+ maxPosNameHeight = maxPosNameHeight == null ? textHeight : Math.max(maxPosNameHeight, textHeight);
1378
1389
  }
1379
1390
  const hScale = maxPosNameWidth! < (positionWidth * dpr - 2) ? 1 : (positionWidth * dpr - 2) / maxPosNameWidth!;
1380
1391