@datagrok/bio 1.7.11 → 1.7.14

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
@@ -2,7 +2,7 @@
2
2
  "name": "@datagrok/bio",
3
3
  "beta": false,
4
4
  "friendlyName": "Bio",
5
- "version": "1.7.11",
5
+ "version": "1.7.14",
6
6
  "description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform",
7
7
  "repository": {
8
8
  "type": "git",
@@ -11,25 +11,25 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@biowasm/aioli": ">=2.4.0",
14
- "@datagrok-libraries/bio": "^2.8.5",
15
- "@datagrok-libraries/utils": "^1.0.0",
16
- "@datagrok-libraries/ml": "^2.0.10",
14
+ "@datagrok-libraries/bio": "^2.8.6",
15
+ "@datagrok-libraries/ml": "^3.0.0",
16
+ "@datagrok-libraries/utils": "^1.4.0",
17
17
  "cash-dom": "latest",
18
- "datagrok-api": "^1.4.12",
19
- "dayjs": "latest",
18
+ "datagrok-api": "^1.5.1",
19
+ "dayjs": "^1.11.4",
20
+ "openchemlib": "6.0.1",
20
21
  "rxjs": "^6.5.5",
21
22
  "ts-loader": "^9.2.5",
22
- "typescript": "^4.4.2",
23
- "openchemlib": "6.0.1"
23
+ "typescript": "^4.4.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/jest": "^27.0.0",
27
27
  "@typescript-eslint/eslint-plugin": "latest",
28
28
  "@typescript-eslint/parser": "latest",
29
- "eslint": "latest",
29
+ "eslint": "^8.20.0",
30
30
  "eslint-config-google": "latest",
31
31
  "jest": "^27.0.0",
32
- "jest-html-reporter": "^3.5.0",
32
+ "jest-html-reporter": "^3.6.0",
33
33
  "puppeteer": "^13.7.0",
34
34
  "ts-jest": "^27.0.0",
35
35
  "webpack": "latest",
@@ -40,16 +40,16 @@
40
40
  "link-bio": "npm link @datagrok-libraries/bio",
41
41
  "link-ml": "npm link @datagrok-libraries/ml",
42
42
  "link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio @datagrok-libraries/ml",
43
- "debug-sequences1": "grok publish --rebuild",
44
- "release-sequences1": "grok publish --rebuild --release",
43
+ "debug-sequences1": "grok publish",
44
+ "release-sequences1": "grok publish --release",
45
45
  "build-sequences1": "webpack",
46
46
  "debug-local": "grok publish local",
47
47
  "release-local": "grok publish local --release",
48
48
  "build": "webpack",
49
- "debug-sequences1-public": "grok publish public --rebuild",
50
- "release-sequences1-public": "grok publish public --rebuild --release",
51
- "debug-sequences1-local": "grok publish local --rebuild",
52
- "release-sequences1-local": "grok publish local --rebuild --release",
49
+ "debug-sequences1-public": "grok publish public",
50
+ "release-sequences1-public": "grok publish public --release",
51
+ "debug-sequences1-local": "grok publish local",
52
+ "release-sequences1-local": "grok publish local --release",
53
53
  "lint": "eslint \"./src/**/*.ts\"",
54
54
  "lint-fix": "eslint \"./src/**/*.ts\" --fix",
55
55
  "test": "jest",
@@ -0,0 +1,13 @@
1
+ #name: Embed
2
+ #language: python
3
+ #input: string molecule
4
+ #output: string sdf
5
+
6
+ from rdkit.Chem import AllChem
7
+ from rdkit import Chem
8
+ mol = AllChem.MolFromMolBlock(molecule) if ("M END" in molecule) else AllChem.MolFromSmiles(molecule)
9
+
10
+ AllChem.EmbedMolecule(mol, AllChem.ETKDG())
11
+ #AllChem.UFFOptimizeMolecule(mol)
12
+ #mol = Chem.RemoveHs(mol)
13
+ sdf = Chem.MolToMolBlock(mol)
package/src/const.ts CHANGED
@@ -23,3 +23,8 @@ export const CAP_GROUP_NAME = 'capGroupName';
23
23
  export const RGROUP_LABEL = 'label';
24
24
  export const MONOMER_SYMBOL = 'symbol';
25
25
  export const SDF_MONOMER_NAME = 'MonomerName';
26
+
27
+ // range of hex nubers used in PepSea library to endode monomers
28
+ export const MONOMER_ENCODE_MIN = 0x100;
29
+ export const MONOMER_ENCODE_MAX = 0x40A;
30
+
package/src/package.ts CHANGED
@@ -16,11 +16,12 @@ import {getEmbeddingColsNames, sequenceSpace} from './utils/sequence-space';
16
16
  import {AvailableMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
17
17
  import {getActivityCliffs} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
18
18
  import {sequenceGetSimilarities, drawTooltip} from './utils/sequence-activity-cliffs';
19
- import {createJsonMonomerLibFromSdf, getMolfilesFromSeq, HELM_CORE_LIB_FILENAME} from './utils/utils';
19
+ import {createJsonMonomerLibFromSdf, encodeMonomers, getMolfilesFromSeq, HELM_CORE_LIB_FILENAME} from './utils/utils';
20
20
  import {getMacroMol} from './utils/atomic-works';
21
21
  import {MacromoleculeSequenceCellRenderer} from './utils/cell-renderer';
22
22
  import {convert} from './utils/convert';
23
23
  import {lru} from './utils/cell-renderer';
24
+ import {representationsWidget} from './widgets/representations';
24
25
 
25
26
  //tags: init
26
27
  export async function initBio(): Promise<void> {
@@ -37,7 +38,6 @@ export function Lru() {
37
38
  return lru;
38
39
  }
39
40
 
40
-
41
41
  //name: macromoleculeSequenceCellRenderer
42
42
  //tags: cellRenderer
43
43
  //meta.cellType: Macromolecule
@@ -112,7 +112,9 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
112
112
  similarity: number, methodName: string): Promise<void> {
113
113
  if (!checkInputColumn(macroMolecule, 'Activity Cliffs'))
114
114
  return;
115
-
115
+ const encodedCol = encodeMonomers(macroMolecule);
116
+ if (!encodedCol)
117
+ return;
116
118
  const axesNames = getEmbeddingColsNames(df);
117
119
  const options = {
118
120
  'SPE': {cycles: 2000, lambda: 1.0, dlambda: 0.0005},
@@ -121,6 +123,7 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
121
123
  await getActivityCliffs(
122
124
  df,
123
125
  macroMolecule,
126
+ encodedCol,
124
127
  axesNames,
125
128
  'Activity cliffs',
126
129
  activities,
@@ -146,10 +149,12 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, macroMolecule: D
146
149
  similarityMetric: string = 'Levenshtein', plotEmbeddings: boolean): Promise<void> {
147
150
  if (!checkInputColumn(macroMolecule, 'Activity Cliffs'))
148
151
  return;
149
-
152
+ const encodedCol = encodeMonomers(macroMolecule);
153
+ if (!encodedCol)
154
+ return;
150
155
  const embedColsNames = getEmbeddingColsNames(table);
151
156
  const chemSpaceParams = {
152
- seqCol: macroMolecule,
157
+ seqCol: encodedCol,
153
158
  methodName: methodName,
154
159
  similarityMetric: similarityMetric,
155
160
  embedAxesNames: embedColsNames
@@ -275,6 +280,17 @@ function parseMacromolecule(
275
280
  return seqArray.join('');
276
281
  }
277
282
 
283
+ //name: Representations
284
+ //tags: panel, widgets
285
+ //input: cell macroMolecule {semType: Macromolecule}
286
+ //output: widget result
287
+ export async function peptideMolecule(macroMolecule: DG.Cell): Promise<DG.Widget> {
288
+ const monomersLibFile = await _package.files.readAsText(HELM_CORE_LIB_FILENAME);
289
+ const monomersLibObject: any[] = JSON.parse(monomersLibFile);
290
+
291
+ return representationsWidget(macroMolecule, monomersLibObject);
292
+ }
293
+
278
294
  //name: importFasta
279
295
  //description: Opens FASTA file
280
296
  //tags: file-handler
@@ -7,6 +7,7 @@ import {readDataframe} from './utils';
7
7
  import {getEmbeddingColsNames, sequenceSpace} from '../utils/sequence-space';
8
8
  import {drawTooltip, sequenceGetSimilarities} from '../utils/sequence-activity-cliffs';
9
9
  import {getActivityCliffs} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
10
+ import { encodeMonomers } from '../utils/utils';
10
11
 
11
12
 
12
13
  category('activityCliffs', async () => {
@@ -31,9 +32,11 @@ category('activityCliffs', async () => {
31
32
  const options = {
32
33
  'SPE': {cycles: 2000, lambda: 1.0, dlambda: 0.0005},
33
34
  };
35
+ const encodedCol = encodeMonomers(actCliffsDf.col('MSA')!) as DG.Column;
34
36
  const scatterPlot = await getActivityCliffs(
35
37
  actCliffsDf,
36
38
  actCliffsDf.col('MSA')!,
39
+ encodedCol,
37
40
  axesNames,
38
41
  'Activity cliffs',
39
42
  actCliffsDf.col('Activity')!,
@@ -4,7 +4,8 @@ import * as grok from 'datagrok-api/grok';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {ConverterFunc} from './types';
7
- import {NOTATION, NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
7
+ import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
8
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/units-handler';
8
9
 
9
10
  // import {mmSemType} from '../const';
10
11
  // import {importFasta} from '../package';
@@ -14,6 +14,13 @@ category('detectors', () => {
14
14
  2
15
15
  3`;
16
16
 
17
+ const csvDfEmpty: string = `id,col1
18
+ 1,
19
+ 2,
20
+ 3,
21
+ 4,
22
+ 5,`;
23
+
17
24
  const csvDf2: string = `col1
18
25
  4
19
26
  5
@@ -179,6 +186,7 @@ MWRSWY-CKHP
179
186
  };
180
187
  };
181
188
 
189
+ test('NegativeEmpty', async () => {await _testNeg(readCsv('csvDfEmpty', csvDfEmpty), 'col1'); });
182
190
  test('Negative1', async () => { await _testNeg(readCsv('csvDf1', csvDf1), 'col1'); });
183
191
  test('Negative2', async () => { await _testNeg(readCsv('csvDf2', csvDf2), 'col1'); });
184
192
  test('Negative3', async () => { await _testNeg(readCsv('csvDf3', csvDf3), 'col1'); });
@@ -5,7 +5,7 @@ import * as DG from 'datagrok-api/dg';
5
5
  import {importFasta, multipleSequenceAlignmentAny} from '../package';
6
6
  import {readDataframe} from './utils';
7
7
  import {convertDo} from '../utils/convert';
8
- import {NOTATION} from '@datagrok-libraries/bio/src/utils/notation-converter';
8
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/units-handler';
9
9
 
10
10
  category('renderers', () => {
11
11
  let tvList: DG.TableView[];
@@ -4,7 +4,8 @@ import * as grok from 'datagrok-api/grok';
4
4
  import $ from 'cash-dom';
5
5
 
6
6
  import {Subscription} from 'rxjs';
7
- import {NotationConverter, NOTATION} from '@datagrok-libraries/bio/src/utils/notation-converter';
7
+ import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
8
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/units-handler';
8
9
 
9
10
 
10
11
  let convertDialog: DG.Dialog | null = null;
@@ -17,7 +18,7 @@ let convertDialogSubs: Subscription[] = [];
17
18
  */
18
19
  export function convert(col: DG.Column): void {
19
20
  const converter = new NotationConverter(col);
20
- const current: NOTATION = converter.sourceNotation;
21
+ const currentNotation: NOTATION = converter.notation;
21
22
  //TODO: read all notations
22
23
  const notations = [
23
24
  NOTATION.FASTA,
@@ -25,7 +26,7 @@ export function convert(col: DG.Column): void {
25
26
  NOTATION.HELM
26
27
  ];
27
28
  const separatorArray = ['-', '.', '/'];
28
- const filteredNotations = notations.filter((e) => e !== current);
29
+ const filteredNotations = notations.filter((e) => e !== currentNotation);
29
30
  const targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations);
30
31
 
31
32
  const separatorInput = ui.choiceInput('Separator', separatorArray[0], separatorArray);
@@ -48,7 +49,7 @@ export function convert(col: DG.Column): void {
48
49
  if (convertDialog == null) {
49
50
  convertDialog = ui.dialog('Convert sequence notation')
50
51
  .add(ui.div([
51
- ui.h1('Current notation: ' + current),
52
+ ui.h1('Current notation: ' + currentNotation),
52
53
  targetNotationInput.root,
53
54
  separatorInput.root
54
55
  ]))
@@ -2,7 +2,7 @@ import * as DG from 'datagrok-api/dg';
2
2
  import {WebLogo, SplitterFunc} from '@datagrok-libraries/bio/src/viewers/web-logo';
3
3
  import * as grok from 'datagrok-api/grok';
4
4
  import {
5
- CAP_GROUP_NAME, CAP_GROUP_SMILES, jsonSdfMonomerLibDict, MONOMER_SYMBOL,
5
+ CAP_GROUP_NAME, CAP_GROUP_SMILES, jsonSdfMonomerLibDict, MONOMER_ENCODE_MAX, MONOMER_ENCODE_MIN, MONOMER_SYMBOL,
6
6
  RGROUP_ALTER_ID, RGROUP_FIELD, RGROUP_LABEL, SDF_MONOMER_NAME
7
7
  } from '../const';
8
8
 
@@ -11,6 +11,33 @@ export const HELM_CORE_LIB_MONOMER_SYMBOL = 'symbol';
11
11
  export const HELM_CORE_LIB_MOLFILE = 'molfile';
12
12
  export const HELM_CORE_FIELDS = ['symbol', 'molfile', 'rgroups', 'name'];
13
13
 
14
+
15
+ export function encodeMonomers(col: DG.Column): DG.Column | null {
16
+ let encodeSymbol = MONOMER_ENCODE_MIN;
17
+ const monomerSymbolDict: { [key: string]: number }= {};
18
+ const units = col.tags[DG.TAGS.UNITS];
19
+ const sep = col.getTag('separator');
20
+ const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, sep);
21
+ const encodedStringArray = [];
22
+ for (let i = 0; i < col.length; ++i) {
23
+ let encodedMonomerStr = '';
24
+ const monomers = splitterFunc(col.get(i));
25
+ monomers.forEach(m => {
26
+ if(!monomerSymbolDict[m]) {
27
+ if(encodeSymbol > MONOMER_ENCODE_MAX) {
28
+ grok.shell.error(`Not enougth symbols to encode monomers`);
29
+ return null;
30
+ }
31
+ monomerSymbolDict[m] = encodeSymbol;
32
+ encodeSymbol++;
33
+ }
34
+ encodedMonomerStr += String.fromCodePoint(monomerSymbolDict[m]);
35
+ })
36
+ encodedStringArray.push(encodedMonomerStr);
37
+ }
38
+ return DG.Column.fromStrings('encodedMolecules', encodedStringArray);
39
+ }
40
+
14
41
  export function getMolfilesFromSeq(col: DG.Column, monomersLibObject: any[]): any[][] | null {
15
42
  const units = col.tags[DG.TAGS.UNITS];
16
43
  const sep = col.getTag('separator');
@@ -18,7 +45,8 @@ export function getMolfilesFromSeq(col: DG.Column, monomersLibObject: any[]): an
18
45
  const monomersDict = createMomomersMolDict(monomersLibObject);
19
46
  const molFiles = [];
20
47
  for (let i = 0; i < col.length; ++i) {
21
- const monomers = splitterFunc(col.get(i));
48
+ const macroMolecule = col.get(i);
49
+ const monomers = splitterFunc(macroMolecule);
22
50
  const molFilesForSeq = [];
23
51
  for (let j = 0; j < monomers.length; ++j) {
24
52
  if (monomers[j]) {
@@ -34,6 +62,28 @@ export function getMolfilesFromSeq(col: DG.Column, monomersLibObject: any[]): an
34
62
  return molFiles;
35
63
  }
36
64
 
65
+ export function getMolfilesFromSingleSeq(cell: DG.Cell, monomersLibObject: any[]): any[][] | null {
66
+ const units = cell.column.tags[DG.TAGS.UNITS];
67
+ const sep = cell.column!.getTag('separator');
68
+ const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, sep);
69
+ const monomersDict = createMomomersMolDict(monomersLibObject);
70
+ const molFiles = [];
71
+ const macroMolecule = cell.value;
72
+ const monomers = splitterFunc(macroMolecule);
73
+ const molFilesForSeq = [];
74
+ for (let j = 0; j < monomers.length; ++j) {
75
+ if (monomers[j]) {
76
+ if (!monomersDict[monomers[j]]) {
77
+ grok.shell.warning(`Monomer ${monomers[j]} is missing in HELM library. Structure cannot be created`);
78
+ return null;
79
+ }
80
+ molFilesForSeq.push(JSON.parse(JSON.stringify(monomersDict[monomers[j]])));
81
+ }
82
+ }
83
+ molFiles.push(molFilesForSeq);
84
+ return molFiles;
85
+ }
86
+
37
87
  export function createMomomersMolDict(lib: any[]): { [key: string]: string | any } {
38
88
  const dict: { [key: string]: string | any } = {};
39
89
  lib.forEach((it) => {
@@ -79,4 +129,4 @@ export function createJsonMonomerLibFromSdf(table: DG.DataFrame): any {
79
129
  resultLib.push(monomer);
80
130
  }
81
131
  return resultLib;
82
- }
132
+ }
@@ -0,0 +1,54 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+ import {getMolfilesFromSingleSeq, HELM_CORE_LIB_FILENAME} from '../utils/utils';
5
+ import {getMacroMol} from '../utils/atomic-works';
6
+
7
+ /**
8
+ * 3D representation widget of macromolecule.
9
+ *
10
+ * @export
11
+ * @param {DG.Cell} macroMolecule macromolecule cell.
12
+ * @return {Promise<DG.Widget>} Widget.
13
+ */
14
+ export async function representationsWidget(macroMolecule: DG.Cell, monomersLibObject: any[]): Promise<DG.Widget> {
15
+ const pi = DG.TaskBarProgressIndicator.create('Creating 3D view');
16
+
17
+ let widgetHost;
18
+ let molBlock3D = '';
19
+ try {
20
+ try {
21
+ const atomicCodes = getMolfilesFromSingleSeq(macroMolecule, monomersLibObject);
22
+ const result = await getMacroMol(atomicCodes!);
23
+ const molBlock2D = result[0];
24
+ molBlock3D = (await grok.functions.call('Bio:Embed', {molBlock2D})) as string;
25
+ } catch (e) {
26
+ console.warn(e);
27
+ }
28
+
29
+ try {
30
+ molBlock3D = molBlock3D.replaceAll('\\n', '\n');
31
+ const stringBlob = new Blob([molBlock3D], {type: 'text/plain'});
32
+ const nglHost = ui.div([], {classes: 'd4-ngl-viewer', id: 'ngl-3d-host'});
33
+
34
+ //@ts-ignore
35
+ const stage = new NGL.Stage(nglHost, {backgroundColor: 'white'});
36
+ //@ts-ignore
37
+ stage.loadFile(stringBlob, {ext: 'sdf'}).then(function(comp: NGL.StructureComponent) {
38
+ stage.setSize(300, 300);
39
+ comp.addRepresentation('ball+stick');
40
+ comp.autoView();
41
+ });
42
+ const sketch = grok.chem.svgMol(molBlock3D);
43
+ const panel = ui.divH([sketch]);
44
+
45
+ widgetHost = ui.div([panel, nglHost]);
46
+ } catch (e) {
47
+ widgetHost = ui.divText('Couldn\'t get peptide structure');
48
+ }
49
+ } catch (e) {
50
+ widgetHost = ui.divText('Couldn\'t get peptide structure');
51
+ }
52
+ pi.close();
53
+ return new DG.Widget(widgetHost);
54
+ }
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit f542cbde.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 92b3a565.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,7 +229,8 @@ header {
229
229
  font-size: 1rem;
230
230
  padding: 0 0.5rem;
231
231
  }
232
- </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit f542cbde.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-20 17:49:40</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">209.758s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">199.086s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Bio.MSA.is_correct : TypeError: Cannot read properties of undefined (reading 'split')
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 92b3a565.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-27 15:30:45</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">209.012s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">198.977s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Bio.MSA.is_correct : TypeError: Cannot read properties of undefined (reading 'split')
233
+ Test result : Bio.activityCliffs.activityCliffsOpen : Error: Expected "105 cliffs", got "2362 cliffs"
233
234
 
234
235
  at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:67:20
235
236
  at Generator.next (&lt;anonymous&gt;)
@@ -262,6 +263,7 @@ Test result : Bio.WebLogo.monomerToText.longMonomerComplexFirstPartShort : OK
262
263
  Test result : Bio.WebLogo.monomerToText.longMonomerComplexFirstPartLong56 : OK
263
264
  Test result : Bio.Palettes.testPaletteN : OK
264
265
  Test result : Bio.Palettes.testPaletteAA : OK
266
+ Test result : Bio.detectors.NegativeEmpty : OK
265
267
  Test result : Bio.detectors.Negative1 : OK
266
268
  Test result : Bio.detectors.Negative2 : OK
267
269
  Test result : Bio.detectors.Negative3 : OK
@@ -310,7 +312,6 @@ Test result : Bio.detectors.samplesTestUnichemSourcesNegativeSrcUrl : OK
310
312
  Test result : Bio.detectors.samplesTestUnichemSourcesNegativeBaseIdUrl : OK
311
313
  Test result : Bio.MSA.test_table.is_not_empty : OK
312
314
  Test result : Bio.sequenceSpace.sequenceSpaceOpens : OK
313
- Test result : Bio.activityCliffs.activityCliffsOpen : OK
314
315
  Test result : Bio.splitters.helm1 : OK
315
316
  Test result : Bio.splitters.helm2 : OK
316
317
  Test result : Bio.splitters.helm3-multichar : OK