@datagrok/peptides 1.0.0 → 1.0.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.
@@ -61,7 +61,8 @@ export class PeptideSpaceViewer extends DG.JsViewer {
61
61
  this.isEmbeddingCreating = true;
62
62
  $(this.root).empty();
63
63
  const viewerHost = ui.waitBox(async () => {
64
- const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount);
64
+ const aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.ALIGNED_SEQUENCE)!;
65
+ const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, aligendSeqCol);
65
66
  this.dataFrame.temp[C.EMBEDDING_STATUS] = true;
66
67
  this.model.edf = edf;
67
68
 
@@ -83,7 +84,20 @@ export class PeptideSpaceViewer extends DG.JsViewer {
83
84
  showYSelector: false, showXSelector: false, showColorSelector: false, showSizeSelector: false,
84
85
  zoomAndFilter: 'no action', axesFollowFilter: false,
85
86
  };
86
- const viewerRoot = edf.plot.scatter(viewerOptions).root;
87
+ const scatterPlot = edf.plot.scatter(viewerOptions);
88
+ const viewerRoot = scatterPlot.root;
89
+
90
+ viewerRoot.addEventListener('mousemove', (ev) => {
91
+ const idx = scatterPlot.hitTest(ev.offsetX, ev.offsetY);
92
+ if (idx != -1) {
93
+ const table = ui.tableFromMap({
94
+ 'Activity': colorCol.get(idx),
95
+ 'Sequence': aligendSeqCol.get(idx),
96
+ 'Row ID': idx,
97
+ });
98
+ ui.tooltip.show(table, ev.clientX, ev.clientY);
99
+ }
100
+ });
87
101
  viewerRoot.style.width = 'auto';
88
102
  this.isEmbeddingCreating = false;
89
103
  viewerHost.style.paddingLeft = 'unset';
@@ -123,22 +137,6 @@ export async function computeWeights(
123
137
  columns.push(DG.Column.fromFloat32Array('~MW', _getMW(columnData)));
124
138
 
125
139
  edf = DG.DataFrame.fromColumns(columns);
126
-
127
- // Add new axes.
128
- // for (const axis of axesNames) {
129
- // const col = table.col(axis);
130
- // const newCol = edf.getCol(axis);
131
-
132
- // // if (col != null) {
133
- // // for (let i = 0; i < newCol.length; ++i) {
134
- // // const v = newCol.get(i);
135
- // // table.set(axis, i, v);
136
- // // }
137
- // // } else
138
- // // table.columns.insert(newCol);
139
- // const columnList = table.columns;
140
- // col !== null ? columnList.replace(col, newCol) : columnList.insert(newCol);
141
- // }
142
140
  } catch (error) {
143
141
  grok.shell.error('Could not compute embeddings. See console for details.');
144
142
  console.error(error);
@@ -25,7 +25,7 @@ export class SARViewerBase extends DG.JsViewer {
25
25
  constructor() {
26
26
  super();
27
27
 
28
- this.scaling = this.string('scaling', 'none', {choices: ['none', 'lg', '-lg']});
28
+ this.scaling = this.string('scaling', '-lg', {choices: ['none', 'lg', '-lg']});
29
29
  this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
30
30
  this.showSubstitution = this.bool('showSubstitution', true);
31
31
  this.maxSubstitutions = this.int('maxSubstitutions', 1);
@@ -1,6 +1,5 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import * as rxjs from 'rxjs';
3
- import * as ui from 'datagrok-api/ui';
4
3
  import {MonomerLibrary} from '../monomer-library';
5
4
 
6
5
  import * as C from '../utils/constants';
@@ -15,7 +14,7 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart): voi
15
14
  const cell = grid.hitTest(ev.offsetX, ev.offsetY);
16
15
  if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.AMINO_ACIDS) {
17
16
  const newBarPart = barchart.findAARandPosition(cell, ev);
18
- barchart._currentBarPart = newBarPart;
17
+ // barchart._currentBarPart = newBarPart;
19
18
  barchart.requestAction(ev, newBarPart);
20
19
  barchart.computeData();
21
20
  }
@@ -24,7 +23,7 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart): voi
24
23
  // The following events makes the barchart interactive
25
24
  rxjs.fromEvent<MouseEvent>(grid.overlay, 'mousemove').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
26
25
  rxjs.fromEvent<MouseEvent>(grid.overlay, 'click').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
27
- rxjs.fromEvent<MouseEvent>(grid.overlay, 'mouseout').subscribe(() => barchart.unhighlight());
26
+ rxjs.fromEvent<MouseEvent>(grid.overlay, 'mouseout').subscribe(() => barchart.computeData());
28
27
 
29
28
  barchart.tableCanvas = grid.canvas;
30
29
 
@@ -32,17 +31,11 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart): voi
32
31
  grid.setOptions({'colHeaderHeight': 130});
33
32
 
34
33
  grid.onCellTooltip((cell, x, y) => {
35
- if (
36
- cell.tableColumn &&
37
- [C.SEM_TYPES.AMINO_ACIDS, C.SEM_TYPES.ALIGNED_SEQUENCE].includes(cell.tableColumn.semType as C.SEM_TYPES)
38
- ) {
34
+ const colSemType = cell.tableColumn?.semType as C.SEM_TYPES;
35
+ if (colSemType == C.SEM_TYPES.ALIGNED_SEQUENCE || colSemType == C.SEM_TYPES.AMINO_ACIDS) {
39
36
  if (!cell.isColHeader) {
40
37
  const monomerLib = cell.cell.dataFrame.temp[MonomerLibrary.id];
41
38
  PeptidesModel.chemPalette.showTooltip(cell, x, y, monomerLib);
42
- } else if (barchart._currentBarPart) {
43
- let elements: HTMLElement[] = [];
44
- elements = elements.concat([ui.divText(barchart._currentBarPart.aaName)]);
45
- ui.tooltip.show(ui.divV(elements), x, y);
46
39
  }
47
40
  }
48
41
  return true;
@@ -68,14 +61,10 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart): voi
68
61
  });
69
62
 
70
63
  grid.temp['containsBarchart'] = true;
71
- //FIXME: for some reason barchat didn't show when running analysis. This fixes it, but it's bad. Find a way to fix
72
- // the problem
73
- barchart.unhighlight();
74
64
  }
75
65
 
76
66
  export class StackedBarChart extends DG.JsViewer {
77
67
  dataEmptyAA: string;
78
- _currentBarPart: type.BarChart.BarPart | null = null;
79
68
  tableCanvas: HTMLCanvasElement | undefined;
80
69
  aminoColumnNames: string[] = [];
81
70
  ord: { [Key: string]: number; } = {};
@@ -121,6 +110,7 @@ export class StackedBarChart extends DG.JsViewer {
121
110
  this.subs.push(DG.debounce(this.dataFrame.filter.onChanged, 50).subscribe((_) => this.computeData()));
122
111
  this.subs.push(DG.debounce(this.dataFrame.onValuesChanged, 50).subscribe(() => this.computeData()));
123
112
  }
113
+ this.computeData();
124
114
  }
125
115
 
126
116
  // Cancel subscriptions when the viewer is detached
@@ -272,6 +262,7 @@ export class StackedBarChart extends DG.JsViewer {
272
262
  });
273
263
  }
274
264
 
265
+ //TODO: refactor and simplify it
275
266
  findAARandPosition(cell: DG.GridCell, mouseEvent: MouseEvent): {colName: string, aaName: string} | null {
276
267
  if (!cell.tableColumn?.name || !this.aminoColumnNames.includes(cell.tableColumn.name))
277
268
  return null;
@@ -315,11 +306,6 @@ export class StackedBarChart extends DG.JsViewer {
315
306
  return null;
316
307
  }
317
308
 
318
- unhighlight(): void {
319
- ui.tooltip.hide();
320
- this.computeData();
321
- }
322
-
323
309
  /** Requests highlight/select/filter action based on currentBarPart */
324
310
  requestAction(event: MouseEvent, barPart: {colName: string, aaName: string} | null): void {
325
311
  if (!barPart)
@@ -329,11 +315,7 @@ export class StackedBarChart extends DG.JsViewer {
329
315
  if (event.type === 'click') {
330
316
  event.shiftKey ? this.model.modifyCurrentSelection(aar, position) :
331
317
  this.model.initCurrentSelection(aar, position);
332
- } else {
333
- ui.tooltip.showRowGroup(this.dataFrame, (i) => {
334
- const currentAAR = this.dataFrame.get(position, i);
335
- return currentAAR === aar;
336
- }, event.offsetX, event.offsetY);
337
- }
318
+ } else
319
+ this.model.showTooltip(aar, position, event.clientX, event.clientY);
338
320
  }
339
321
  }
@@ -6,6 +6,7 @@ import * as C from '../utils/constants';
6
6
  import {getSeparator} from '../utils/misc';
7
7
  import {PeptidesModel} from '../model';
8
8
  import {_package} from '../package';
9
+ import $ from 'cash-dom';
9
10
 
10
11
  /** Peptide analysis widget.
11
12
  *
@@ -63,12 +64,21 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
63
64
  });
64
65
  startBtn.style.alignSelf = 'center';
65
66
 
66
- const viewer = await currentDf.plot.fromType('WebLogo');
67
- viewer.root.style.setProperty('height', '130px');
67
+ const bioList = (await grok.dapi.packages.list({filter: 'name = "Bio"'})).filter(p => p.name == 'Bio');
68
+ const logoHost = ui.div('Install Bio package to see WebLogo');
69
+ if (bioList.length > 0) {
70
+ const viewer = await currentDf.plot.fromType('WebLogo');
71
+ viewer.root.style.setProperty('height', '130px');
72
+ $(logoHost).empty().append(viewer.root);
73
+ } else {
74
+ logoHost.style.color = DG.Color.toHtml(DG.Color.red);
75
+ logoHost.style.alignSelf = 'center';
76
+ logoHost.style.margin = '10px';
77
+ }
68
78
 
69
79
  return new DG.Widget(
70
80
  ui.divV([
71
- viewer.root,
81
+ logoHost,
72
82
  ui.splitH([
73
83
  ui.splitV([ui.inputs(inputsList), startBtn]),
74
84
  histogramHost,
@@ -1,77 +1,186 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
 
4
- import * as C from '../utils/constants';
5
4
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
- import {FilteringStatistics} from '../utils/filtering-statistics';
7
- import * as type from '../utils/types';
8
-
9
- export function getDistributionPlot(df: DG.DataFrame, valueCol: string, splitCol: string): DG.Viewer {
10
- return df.plot.histogram({
11
- filteringEnabled: false,
12
- valueColumnName: valueCol,
13
- splitColumnName: splitCol,
14
- legendVisibility: 'Never',
15
- showXAxis: true,
16
- showColumnSelector: false,
17
- showRangeSlider: false,
18
- });
19
- }
5
+ import $ from 'cash-dom';
20
6
 
21
- const allLabel = 'All';
7
+ import * as C from '../utils/constants';
8
+ import {getStats, Stats} from '../utils/filtering-statistics';
9
+ import {PeptidesModel} from '../model';
22
10
 
23
- export function getDistributionWidget(table: DG.DataFrame): DG.Widget {
24
- const splitCol = table.col(C.COLUMNS_NAMES.SPLIT_COL);
25
- const selectionObject: type.SelectionObject = JSON.parse(table.tags[C.TAGS.SELECTION]);
26
- if (!splitCol || !selectionObject)
27
- return new DG.Widget(ui.divText('No distribution'));
11
+ const allConst = 'All';
12
+ const otherConst = 'Other';
28
13
 
14
+ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
15
+ const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
16
+ const rowCount = activityScaledCol.length;
17
+ const selectionObject = model.currentSelection;
29
18
  const positions = Object.keys(selectionObject);
30
- let currentColor = DG.Color.toHtml(DG.Color.blue);
31
- const otherColor = DG.Color.toHtml(DG.Color.blue);
32
- let aarStr = allLabel;
19
+ const positionsLen = positions.length;
20
+ let aarStr = allConst;
33
21
  let otherStr = '';
22
+ const useSelectedStr = model.isPeptideSpaceChangingBitset;
34
23
 
35
- if (positions.length) {
36
- aarStr = '';
24
+ const updateDistributionHost = () => {
25
+ model.splitByPos = splitByPosition.value!;
26
+ model.splitByAAR = splitByAAR.value!;
27
+ const res: HTMLDivElement[] = [];
28
+ if (splitByPosition.value && splitByAAR.value) {
29
+ otherStr = otherConst;
30
+ for (const position of positions) {
31
+ const posCol = table.getCol(position);
32
+ for (const aar of selectionObject[position]) {
33
+ aarStr = `${position} : ${aar}`;
34
+ const splitCol = DG.Column.bool(C.COLUMNS_NAMES.SPLIT_COL, rowCount).init((i) => posCol.get(i) == aar);
37
35
 
38
- for (const position of positions) {
39
- aarStr += `${position}: {`;
36
+ const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
37
+ const currentStatsDf = model.statsDf.rows.match({Pos: position, AAR: aar}).toDataFrame();
38
+ const stats: Stats = {
39
+ count: currentStatsDf.get(C.COLUMNS_NAMES.COUNT, 0),
40
+ ratio: currentStatsDf.get(C.COLUMNS_NAMES.RATIO, 0),
41
+ pValue: currentStatsDf.get(C.COLUMNS_NAMES.P_VALUE, 0),
42
+ meanDifference: currentStatsDf.get(C.COLUMNS_NAMES.MEAN_DIFFERENCE, 0),
43
+ };
44
+ const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr, true);
45
+ $(distributionRoot).addClass('d4-flex-col');
40
46
 
41
- for (const aar of selectionObject[position])
42
- aarStr += `${aar}, `;
47
+ res.push(distributionRoot);
48
+ }
49
+ }
50
+ } else if (splitByPosition.value) {
51
+ otherStr = otherConst;
52
+ const activityScaledData = activityScaledCol.getRawData();
53
+ for (const position of positions) {
54
+ const posCol = table.getCol(position);
55
+ const aarList = selectionObject[position];
56
+ aarStr = `${position}: {${aarList.join(', ')}}`;
43
57
 
44
- aarStr = aarStr.slice(0, aarStr.length - 2);
45
- aarStr += '}; ';
46
- }
47
- aarStr = aarStr.slice(0, aarStr.length - 2);
48
- otherStr = 'Other';
49
- currentColor = DG.Color.toHtml(DG.Color.orange);
50
- }
51
-
52
- const currentLabel = ui.label(aarStr, {style: {color: currentColor}});
53
- const otherLabel = ui.label(otherStr, {style: {color: otherColor}});
54
- const elements: (HTMLLabelElement | HTMLElement)[] = [currentLabel, otherLabel];
55
-
56
- const getContent = (): HTMLDivElement => {
57
- const valueColName = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!.name;
58
- const hist = getDistributionPlot(table, valueColName, C.COLUMNS_NAMES.SPLIT_COL).root;
59
- hist.style.width = 'auto';
60
- elements.push(hist);
61
- const stats = (table.temp[C.STATS] as FilteringStatistics).result;
62
-
63
- if (stats && aarStr != allLabel) {
64
- const tableMap: StringDictionary = {
65
- 'Statistics:': '',
66
- 'Count': stats.count.toString(),
67
- 'p-value': stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(2),
68
- 'Mean difference': stats.meanDifference.toFixed(2),
69
- };
70
-
71
- elements.push(ui.tableFromMap(tableMap));
58
+ const mask = DG.BitSet.create(rowCount, (i) => aarList.includes(posCol.get(i)));
59
+ const stats = getStats(activityScaledData, mask);
60
+ const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
61
+ const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
62
+ const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr, true);
63
+ $(distributionRoot).addClass('d4-flex-col');
64
+
65
+ res.push(distributionRoot);
66
+ }
67
+ } else if (splitByAAR.value) {
68
+ const reversedSelectionObject: {[aar: string]: string[]} = {};
69
+ const aars = [];
70
+ for (const position of positions) {
71
+ for (const aar of selectionObject[position]) {
72
+ if (!reversedSelectionObject.hasOwnProperty(aar)) {
73
+ reversedSelectionObject[aar] = [position];
74
+ aars.push(aar);
75
+ continue;
76
+ }
77
+ if (!reversedSelectionObject[aar].includes(position))
78
+ reversedSelectionObject[aar].push(position);
79
+ }
80
+ }
81
+
82
+ otherStr = otherConst;
83
+ const activityScaledData = activityScaledCol.getRawData();
84
+ for (const aar of aars) {
85
+ const posList = reversedSelectionObject[aar];
86
+ aarStr = `${aar}: {${posList.join(', ')}}`;
87
+
88
+ const mask = DG.BitSet.create(rowCount, (i) => {
89
+ const currentRow = table.row(i);
90
+ for (const position of posList) {
91
+ if (currentRow.get(position) == aar)
92
+ return true;
93
+ }
94
+ return false;
95
+ });
96
+ const stats = getStats(activityScaledData, mask);
97
+ const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
98
+ const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
99
+ const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr, true);
100
+ $(distributionRoot).addClass('d4-flex-col');
101
+
102
+ res.push(distributionRoot);
103
+ }
104
+ } else {
105
+ const splitCol = table.col(C.COLUMNS_NAMES.SPLIT_COL);
106
+ if (!splitCol)
107
+ return new DG.Widget(ui.divText('No distribution'));
108
+
109
+ otherStr = '';
110
+ if (useSelectedStr) {
111
+ aarStr = 'Selected';
112
+ otherStr = otherConst;
113
+ } else if (positionsLen) {
114
+ aarStr = '';
115
+ for (const position of positions)
116
+ aarStr += `${position}: {${selectionObject[position].join(', ')}}; `;
117
+ aarStr = aarStr.slice(0, aarStr.length - 2);
118
+ otherStr = otherConst;
119
+ }
120
+
121
+ const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
122
+ const stats = getStats(activityScaledCol.getRawData(), table.selection);
123
+ const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr);
124
+ $(distributionRoot).addClass('d4-flex-col');
125
+
126
+ res.push(distributionRoot);
72
127
  }
73
- return ui.divV(elements);
128
+ $(distributionHost).empty().append(res);
129
+ };
130
+
131
+ const setDefaultProperties = (input: DG.InputBase) => {
132
+ input.enabled = positionsLen != 0;
133
+ $(input.root).find('.ui-input-editor').css('margin', '0px');
134
+ $(input.root).find('.ui-input-bool-deco').css('left', '-35px').css('margin-right', '-35px');
135
+ $(input.root).find('.ui-input-description').css('padding', '0px');
136
+ };
137
+
138
+ const splitByPosition = ui.boolInput('', model.splitByPos, updateDistributionHost);
139
+ splitByPosition.addPostfix('Split by position');
140
+ setDefaultProperties(splitByPosition);
141
+ $(splitByPosition.root).css('margin-right', '10px');
142
+ const splitByAAR = ui.boolInput('', model.splitByAAR, updateDistributionHost);
143
+ splitByAAR.addPostfix('Split by monomer');
144
+ setDefaultProperties(splitByAAR);
145
+
146
+ const controlsHost = ui.divH([splitByPosition.root, splitByAAR.root]);
147
+ const distributionHost = ui.div([], 'd4-flex-wrap');
148
+ splitByAAR.fireChanged();
149
+
150
+ return new DG.Widget(ui.divV([controlsHost, distributionHost]));
151
+ }
152
+
153
+ export function getDistributionAndStats(
154
+ table: DG.DataFrame, stats: Stats, thisLabel: string, otherLabel: string = '', isTooltip: boolean = false,
155
+ ): HTMLDivElement {
156
+ const labels = ui.divV([
157
+ ui.label(thisLabel, {style: {color: DG.Color.toHtml(otherLabel == '' ? DG.Color.blue : DG.Color.orange)}}),
158
+ ui.label(otherLabel, {style: {color: DG.Color.toHtml(DG.Color.blue)}})]);
159
+
160
+ const histRoot = table.plot.histogram({
161
+ filteringEnabled: false,
162
+ valueColumnName: table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)?.name,
163
+ splitColumnName: C.COLUMNS_NAMES.SPLIT_COL,
164
+ legendVisibility: 'Never',
165
+ showXAxis: true,
166
+ showColumnSelector: false,
167
+ showRangeSlider: false,
168
+ showBinSelector: !isTooltip,
169
+ backColor: isTooltip ? '#fdffe5' : '#fffff',
170
+ }).root;
171
+ histRoot.style.width = 'auto';
172
+
173
+ const tableMap: StringDictionary = {
174
+ 'Statistics:': '',
175
+ 'Count': stats.count.toString(),
176
+ 'Ratio': stats.ratio.toFixed(2),
177
+ 'p-value': stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(2),
178
+ 'Mean difference': stats.meanDifference.toFixed(2),
74
179
  };
75
180
 
76
- return new DG.Widget(getContent());
181
+ const result = ui.divV([labels, histRoot, ui.tableFromMap(tableMap)]);
182
+ result.style.minWidth = '200px';
183
+ if (isTooltip)
184
+ histRoot.style.maxHeight = '150px';
185
+ return result;
77
186
  }
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=69a4761f6044. Commit 40ac3a0c.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 4210edfc.</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,7 @@ 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">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=69a4761f6044. Commit 40ac3a0c.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-01 16:42:11</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/Peptides/src/__jest__/remote.test.ts</div><div class="suite-time warn">112.158s</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">100.002s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: thrown: "Exceeded timeout of 100000 ms for a test.
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 4210edfc.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-08 12:49:24</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/Peptides/src/__jest__/remote.test.ts</div><div class="suite-time warn">113.293s</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">100.003s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: thrown: "Exceeded timeout of 100000 ms for a test.
233
233
  Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
234
234
  at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:22:1)
235
235
  at Runtime._execModule (/home/runner/work/public/public/packages/Peptides/node_modules/jest-runtime/build/index.js:1646:24)