@datagrok/peptides 1.3.0 → 1.3.2

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/src/tests/core.ts CHANGED
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
  import {category, test, expect, delay} from '@datagrok-libraries/utils/src/test';
5
5
 
6
6
  import {_package} from '../package-test';
7
- import {startAnalysis} from '../widgets/analyze-peptides';
7
+ import {startAnalysis} from '../widgets/peptides';
8
8
  import {PeptidesModel} from '../model';
9
9
  import * as C from '../utils/constants';
10
10
  import {scaleActivity} from '../utils/misc';
@@ -14,6 +14,7 @@ category('Core', () => {
14
14
  let simpleActivityCol: DG.Column<number>;
15
15
  let simpleAlignedSeqCol: DG.Column<string>;
16
16
  let simpleScaledDf: DG.DataFrame;
17
+ let scalingFormula: (x: number) => number;
17
18
  let simpleScaledColName: string;
18
19
 
19
20
  let complexTable: DG.DataFrame;
@@ -34,10 +35,10 @@ category('Core', () => {
34
35
  simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
35
36
  simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
36
37
  simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
37
- [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
38
+ [simpleScaledDf, scalingFormula, simpleScaledColName] = scaleActivity('-lg', simpleActivityCol);
38
39
 
39
40
  model = await startAnalysis(
40
- simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledDf, simpleScaledColName);
41
+ simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, scalingFormula, simpleScaledColName, '-lg', []);
41
42
  expect(model instanceof PeptidesModel, true);
42
43
 
43
44
  if (model != null) {
@@ -56,10 +57,10 @@ category('Core', () => {
56
57
  complexAlignedSeqCol.tags[DG.TAGS.UNITS] = 'separator';
57
58
  complexAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
58
59
  complexAlignedSeqCol.tags[C.TAGS.SEPARATOR] = '/';
59
- [complexScaledDf, complexScaledColName] = scaleActivity('-lg', complexTable, complexActivityColName, true);
60
+ [complexScaledDf, scalingFormula, complexScaledColName] = scaleActivity('-lg', complexActivityCol);
60
61
 
61
62
  model = await startAnalysis(
62
- complexActivityCol, complexAlignedSeqCol, null, complexTable, complexScaledDf, complexScaledColName);
63
+ complexActivityCol, complexAlignedSeqCol, null, complexTable, scalingFormula, complexScaledColName, '-lg', []);
63
64
  expect(model instanceof PeptidesModel, true);
64
65
 
65
66
  if (model != null) {
@@ -77,10 +78,10 @@ category('Core', () => {
77
78
  simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
78
79
  simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
79
80
  simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
80
- [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
81
+ [simpleScaledDf, scalingFormula, simpleScaledColName] = scaleActivity('-lg', simpleActivityCol);
81
82
 
82
83
  model = await startAnalysis(
83
- simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledDf, simpleScaledColName);
84
+ simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, scalingFormula, simpleScaledColName, '-lg', []);
84
85
  let v = grok.shell.getTableView('Peptides analysis');
85
86
  const d = v.dataFrame;
86
87
  const layout = v.saveLayout();
@@ -89,6 +89,18 @@ export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D,
89
89
  renderCellSelection(canvasContext, bound);
90
90
  }
91
91
 
92
+ export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, cellValue: number,
93
+ clusterSelection: number[], bound: DG.Rect): void {
94
+ canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
95
+ canvasContext.textAlign = 'center';
96
+ canvasContext.textBaseline = 'middle';
97
+ canvasContext.fillStyle = '#000';
98
+ canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
99
+
100
+ if (clusterSelection.includes(cellValue))
101
+ renderCellSelection(canvasContext, bound);
102
+ }
103
+
92
104
  export function renderBarchart(ctx: CanvasRenderingContext2D, col: DG.Column, monomerColStats: types.MonomerColStats,
93
105
  bounds: DG.Rect, max: number): types.BarCoordinates {
94
106
  let sum = col.length - (monomerColStats['-']?.count ?? 0);
@@ -9,7 +9,8 @@ export enum COLUMNS_NAMES {
9
9
  MEAN_DIFFERENCE = 'Mean difference',
10
10
  COUNT = 'Count',
11
11
  RATIO = 'Ratio',
12
- CLUSTERS = '~clusters',
12
+ CLUSTERS = 'clusters',
13
+ MACROMOLECULE = 'macromolecule',
13
14
  }
14
15
 
15
16
  export enum CATEGORIES {
@@ -18,13 +19,16 @@ export enum CATEGORIES {
18
19
  }
19
20
 
20
21
  export enum TAGS {
21
- AAR = 'AAR',
22
- POSITION = 'Pos',
22
+ MONOMER = 'monomer',
23
+ POSITION = 'pos',
23
24
  SEPARATOR = 'separator',
24
25
  SELECTION = 'selection',
25
26
  ALPHABET = 'alphabet',
26
27
  FILTER = 'filter',
27
28
  CLUSTERS = 'clusters',
29
+ SAR_MODE = 'sarMode',
30
+ CLUSTER_SELECTION = 'clusterSelection',
31
+ VISIBLE = 'visible',
28
32
  }
29
33
 
30
34
  export enum SEM_TYPES {
package/src/utils/misc.ts CHANGED
@@ -32,38 +32,33 @@ export function getSeparator(col: DG.Column<string>): string {
32
32
  return col.getTag(C.TAGS.SEPARATOR) ?? '';
33
33
  }
34
34
 
35
- export function scaleActivity(
36
- activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
37
- ): [DG.DataFrame, string] {
38
- let currentActivityColName = originalActivityName ?? C.COLUMNS_NAMES.ACTIVITY;
39
- const flag = df.columns.names().includes(currentActivityColName) &&
40
- currentActivityColName === originalActivityName;
41
- currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
42
- const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
35
+ export function scaleActivity(activityScaling: string, activityCol: DG.Column<number>, indexes?: number[],
36
+ ): [DG.DataFrame, (x: number) => number, string] {
37
+ const tempDf = DG.DataFrame.create(activityCol.length);
43
38
 
44
- let formula = (v: number): number => v;
39
+ let formula = (x: number): number => x;
45
40
  let newColName = 'activity';
46
41
  switch (activityScaling) {
47
42
  case 'none':
48
43
  break;
49
44
  case 'lg':
50
- formula = (v: number): number => Math.log10(v);
45
+ formula = (x: number): number => Math.log10(x);
51
46
  newColName = `Log10(${newColName})`;
52
47
  break;
53
48
  case '-lg':
54
- formula = (v: number): number => -Math.log10(v);
49
+ formula = (x: number): number => -Math.log10(x);
55
50
  newColName = `-Log10(${newColName})`;
56
51
  break;
57
52
  default:
58
53
  throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
59
54
  }
55
+ tempDf.columns.addNewVirtual(
56
+ C.COLUMNS_NAMES.ACTIVITY_SCALED, (i) => {
57
+ const val = activityCol.get(indexes ? indexes[i] : i);
58
+ return val ? formula(val) : val;
59
+ }, DG.TYPE.FLOAT);
60
60
 
61
- const asCol = tempDf.columns.addNewFloat(C.COLUMNS_NAMES.ACTIVITY_SCALED);
62
- const activityCol = df.getCol(currentActivityColName);
63
- asCol.init((i) => formula(activityCol.get(i)));
64
- df.tags['scaling'] = activityScaling;
65
-
66
- return [tempDf, newColName];
61
+ return [tempDf, formula, newColName];
67
62
  }
68
63
 
69
64
  export function calculateBarsData(columns: DG.Column<string>[], selection: DG.BitSet): type.MonomerDfStats {
@@ -44,7 +44,8 @@ export async function createPeptideSimilaritySpaceViewer(
44
44
  const pi = DG.TaskBarProgressIndicator.create('Creating embedding...');
45
45
 
46
46
  const axesNames = ['~X', '~Y', '~MW'];
47
- col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
47
+ // col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
48
+ col ??= table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
48
49
  const columnData = col.toList().map((v) => AlignedSequenceEncoder.clean(v));
49
50
 
50
51
  const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
@@ -1,12 +1,11 @@
1
- import * as grok from 'datagrok-api/grok';
2
1
  import * as ui from 'datagrok-api/ui';
3
2
  import * as DG from 'datagrok-api/dg';
4
3
 
5
4
  import $ from 'cash-dom';
6
- import * as C from '../utils/constants';
7
5
  import {PeptidesModel} from '../model';
8
6
 
9
7
  export class LogoSummary extends DG.JsViewer {
8
+ _titleHost = ui.divText('Logo Summary Table', {id: 'pep-viewer-title'});
10
9
  model!: PeptidesModel;
11
10
  viewerGrid!: DG.Grid;
12
11
  initialized: boolean = false;
@@ -19,7 +18,7 @@ export class LogoSummary extends DG.JsViewer {
19
18
  super.onTableAttached();
20
19
 
21
20
  this.model = await PeptidesModel.getInstance(this.dataFrame);
22
-
21
+
23
22
  this.subs.push(this.model.onLogoSummaryGridChanged.subscribe((grid) => {
24
23
  this.viewerGrid = grid;
25
24
  this.render();
@@ -30,12 +29,13 @@ export class LogoSummary extends DG.JsViewer {
30
29
  this.render();
31
30
  }
32
31
 
33
- detach(): void {this.subs.forEach(sub => sub.unsubscribe());}
32
+ detach(): void {this.subs.forEach((sub) => sub.unsubscribe());}
34
33
 
35
34
  render(): void {
36
35
  if (this.initialized) {
37
36
  $(this.root).empty();
38
- this.root.appendChild(this.viewerGrid.root);
37
+ this.viewerGrid.root.style.width = 'auto';
38
+ this.root.appendChild(ui.divV([this._titleHost, this.viewerGrid.root]));
39
39
  this.viewerGrid.invalidate();
40
40
  }
41
41
  }
@@ -61,8 +61,9 @@ 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 aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
65
- const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, aligendSeqCol);
64
+ // const aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
65
+ const alignedSeqCol = this.dataFrame.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
66
+ const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, alignedSeqCol);
66
67
  this.dataFrame.temp[C.EMBEDDING_STATUS] = true;
67
68
  this.model.edf = edf;
68
69
 
@@ -92,7 +93,7 @@ export class PeptideSpaceViewer extends DG.JsViewer {
92
93
  if (idx != -1) {
93
94
  const table = ui.tableFromMap({
94
95
  'Activity': colorCol.get(idx),
95
- 'Sequence': aligendSeqCol.get(idx),
96
+ 'Sequence': alignedSeqCol.get(idx),
96
97
  'Row ID': idx,
97
98
  });
98
99
  ui.tooltip.show(table, ev.clientX, ev.clientY);
@@ -117,7 +118,8 @@ export async function computeWeights(
117
118
  let edf: DG.DataFrame | null = null;
118
119
  try {
119
120
  const axesNames = ['~X', '~Y', '~MW'];
120
- col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
121
+ // col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
122
+ col ??= table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
121
123
  const columnData = col.toList().map((v) => AlignedSequenceEncoder.clean(v));
122
124
 
123
125
  const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
@@ -21,6 +21,7 @@ export class SARViewerBase extends DG.JsViewer {
21
21
  initialized = false;
22
22
  isPropertyChanging: boolean = false;
23
23
  _isVertical = false;
24
+ isModeChanging = false;
24
25
 
25
26
  constructor() {
26
27
  super();
@@ -52,20 +53,52 @@ export class SARViewerBase extends DG.JsViewer {
52
53
 
53
54
  detach(): void {this.subs.forEach((sub) => sub.unsubscribe());}
54
55
 
56
+ get state(): string {
57
+ return this.dataFrame.getTag(C.TAGS.SAR_MODE) ?? '10';
58
+ }
59
+ set state(s: string) {
60
+ this.dataFrame.setTag(C.TAGS.SAR_MODE, s);
61
+ }
62
+
55
63
  render(refreshOnly = false): void {
56
64
  if (!this.initialized)
57
65
  return;
58
66
  if (!refreshOnly) {
59
67
  $(this.root).empty();
60
- const switchHost = ui.div();
68
+ let switchHost = ui.div();
61
69
  if (this.name == 'MC') {
62
- const modeSwitch = ui.switchInput('Invariant Map', this.model.isInvariantMap, () => {
63
- this.model.isInvariantMap = modeSwitch.value;
64
- this._titleHost.innerText = modeSwitch.value ? 'Invariant Map' : 'Mutation Cliffs';
70
+ const mutationCliffsMode = ui.boolInput('', this.state[0] === '1', () => {
71
+ if (this.isModeChanging)
72
+ return;
73
+ this.isModeChanging = true;
74
+ invariantMapMode.value = !invariantMapMode.value;
75
+ this.isModeChanging = false;
76
+ this._titleHost.innerText = 'Mutation Cliffs';
77
+ this.model.isInvariantMap = false;
78
+ this.viewerGrid.invalidate();
79
+ });
80
+ mutationCliffsMode.addPostfix('Mutation Cliffs');
81
+ const invariantMapMode = ui.boolInput('', this.state[1] === '1', () => {
82
+ if (this.isModeChanging)
83
+ return;
84
+ this.isModeChanging = true;
85
+ mutationCliffsMode.value = !mutationCliffsMode.value;
86
+ this.isModeChanging = false;
87
+ this._titleHost.innerText = 'Invariant Map';
88
+ this.model.isInvariantMap = true;
65
89
  this.viewerGrid.invalidate();
66
90
  });
67
- modeSwitch.root.style.position = 'absolute';
68
- switchHost.appendChild(modeSwitch.root);
91
+ invariantMapMode.addPostfix('Invariant Map');
92
+ const setDefaultProperties = (input: DG.InputBase): void => {
93
+ $(input.root).find('.ui-input-editor').css('margin', '0px').attr('type', 'radio');
94
+ $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
95
+ };
96
+ setDefaultProperties(mutationCliffsMode);
97
+ setDefaultProperties(invariantMapMode);
98
+ $(mutationCliffsMode.root).css('padding-right', '10px').css('padding-left', '5px');
99
+
100
+ switchHost = ui.divH([mutationCliffsMode.root, invariantMapMode.root]);
101
+ switchHost.style.position = 'absolute';
69
102
  }
70
103
  const viewerRoot = this.viewerGrid.root;
71
104
  viewerRoot.style.width = 'auto';
@@ -15,6 +15,10 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
15
15
  const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
16
16
  const rowCount = activityScaledCol.length;
17
17
  const selectionObject = model.mutationCliffsSelection;
18
+ let isMutationCliffsSelectionEmpty = true;
19
+ for (const aarList of Object.values(selectionObject))
20
+ isMutationCliffsSelectionEmpty &&= aarList.length === 0;
21
+ const clustersObject = model.logoSummarySelection;
18
22
  const positions = Object.keys(selectionObject);
19
23
  const positionsLen = positions.length;
20
24
  let aarStr = allConst;
@@ -29,12 +33,16 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
29
33
  otherStr = otherConst;
30
34
  for (const position of positions) {
31
35
  const posCol = table.getCol(position);
32
- for (const aar of selectionObject[position]) {
36
+ const aarList = selectionObject[position];
37
+ if (aarList.length === 0)
38
+ continue;
39
+
40
+ for (const aar of aarList) {
33
41
  aarStr = `${position} : ${aar}`;
34
42
  const splitCol = DG.Column.bool(C.COLUMNS_NAMES.SPLIT_COL, rowCount).init((i) => posCol.get(i) == aar);
35
43
 
36
44
  const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
37
- const currentStatsDf = model.statsDf.rows.match({Pos: position, AAR: aar}).toDataFrame();
45
+ const currentStatsDf = model.monomerPositionStatsDf.rows.match({Pos: position, AAR: aar}).toDataFrame();
38
46
  const stats: Stats = {
39
47
  count: currentStatsDf.get(C.COLUMNS_NAMES.COUNT, 0),
40
48
  ratio: currentStatsDf.get(C.COLUMNS_NAMES.RATIO, 0),
@@ -49,10 +57,13 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
49
57
  }
50
58
  } else if (splitByPosition.value) {
51
59
  otherStr = otherConst;
52
- const activityScaledData = activityScaledCol.getRawData();
60
+ const activityScaledData = activityScaledCol.toList();
53
61
  for (const position of positions) {
54
62
  const posCol = table.getCol(position);
55
63
  const aarList = selectionObject[position];
64
+ if (aarList.length === 0)
65
+ continue;
66
+
56
67
  aarStr = `${position}: {${aarList.join(', ')}}`;
57
68
 
58
69
  const mask = DG.BitSet.create(rowCount, (i) => aarList.includes(posCol.get(i)));
@@ -80,7 +91,7 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
80
91
  }
81
92
 
82
93
  otherStr = otherConst;
83
- const activityScaledData = activityScaledCol.getRawData();
94
+ const activityScaledData = activityScaledCol.toList();
84
95
  for (const aar of aars) {
85
96
  const posList = reversedSelectionObject[aar];
86
97
  aarStr = `${aar}: {${posList.join(', ')}}`;
@@ -112,14 +123,18 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
112
123
  otherStr = otherConst;
113
124
  } else if (positionsLen) {
114
125
  aarStr = '';
115
- for (const position of positions)
116
- aarStr += `${position}: {${selectionObject[position].join(', ')}}; `;
117
- aarStr = aarStr.slice(0, aarStr.length - 2);
126
+ for (const position of positions) {
127
+ const aarList = selectionObject[position];
128
+ if (aarList.length !== 0)
129
+ aarStr += `${position}: {${aarList.join(', ')}}; `;
130
+ }
131
+ if (clustersObject.length !== 0)
132
+ aarStr += `Clusters: ${clustersObject.join(', ')}`;
118
133
  otherStr = otherConst;
119
134
  }
120
135
 
121
136
  const distributionTable = DG.DataFrame.fromColumns([activityScaledCol, splitCol]);
122
- const stats = getStats(activityScaledCol.getRawData(), table.selection);
137
+ const stats = getStats(activityScaledCol.toList(), table.selection);
123
138
  const distributionRoot = getDistributionAndStats(distributionTable, stats, aarStr, otherStr);
124
139
  $(distributionRoot).addClass('d4-flex-col');
125
140
 
@@ -130,9 +145,9 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
130
145
  };
131
146
 
132
147
  const setDefaultProperties = (input: DG.InputBase): void => {
133
- input.enabled = positionsLen != 0;
148
+ input.enabled = !isMutationCliffsSelectionEmpty;
134
149
  $(input.root).find('.ui-input-editor').css('margin', '0px');
135
- $(input.root).find('.ui-input-description').css('padding', '0px');
150
+ $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
136
151
  };
137
152
 
138
153
  const splitByPosition = ui.boolInput('', model.splitByPos, updateDistributionHost);
@@ -16,7 +16,8 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
16
16
  const substitutionsArray: string[] = [];
17
17
  const deltaArray: number[] = [];
18
18
  const substitutedToArray: string[] = [];
19
- const alignedSeqCol = table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
19
+ // const alignedSeqCol = table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
20
+ const alignedSeqCol = table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
20
21
  const activityScaledCol = table.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
21
22
  const seenIndexes = new Map<number, number[]>();
22
23
 
@@ -12,10 +12,10 @@ import {scaleActivity} from '../utils/misc';
12
12
 
13
13
  /** Peptide analysis widget.
14
14
  *
15
- * @param {DG.DataFrame} currentDf Working table
15
+ * @param {DG.DataFrame} df Working table
16
16
  * @param {DG.Column} col Aligned sequence column
17
17
  * @return {Promise<DG.Widget>} Widget containing peptide analysis */
18
- export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
18
+ export async function analyzePeptidesWidget(df: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
19
19
  if (!col.tags['aligned']?.includes('MSA') && col.tags[DG.TAGS.UNITS].toLowerCase() != 'helm')
20
20
  return new DG.Widget(ui.divText('Peptides analysis only works with aligned sequences'));
21
21
 
@@ -30,19 +30,27 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
30
30
  let tempCol = null;
31
31
  let scaledDf: DG.DataFrame;
32
32
  let newScaledColName: string;
33
+ let scalingFormula: (x: number) => number;
33
34
 
34
- for (const column of currentDf.columns.numerical)
35
+ for (const column of df.columns.numerical)
35
36
  tempCol = column.type === DG.TYPE.FLOAT ? column : null;
36
37
 
37
- const defaultColumn: DG.Column<number> | null = currentDf.col('activity') || currentDf.col('IC50') || tempCol;
38
+ const defaultActivityColumn: DG.Column<number> | null = df.col('activity') || df.col('IC50') || tempCol;
38
39
  const histogramHost = ui.div([], {id: 'pep-hist-host'});
39
40
 
41
+ const indexes: number[] = [];
42
+ const f = df.filter;
43
+ df.onFilterChanged.subscribe(() => {
44
+ for (let i = 0; i < f.length; ++i) {
45
+ if (f.get(i))
46
+ indexes.push(i);
47
+ }
48
+ });
40
49
  const activityScalingMethod = ui.choiceInput(
41
50
  'Scaling', 'none', ['none', 'lg', '-lg'],
42
51
  async (currentMethod: string): Promise<void> => {
43
- const currentActivityCol = activityColumnChoice.value?.name;
44
-
45
- [scaledDf, newScaledColName] = scaleActivity(currentMethod, currentDf, currentActivityCol, true);
52
+ [scaledDf, scalingFormula, newScaledColName] =
53
+ scaleActivity(currentMethod, activityColumnChoice.value!, indexes.length !== 0 ? indexes : undefined);
46
54
 
47
55
  const hist = scaledDf.plot.histogram({
48
56
  filteringEnabled: false,
@@ -60,23 +68,23 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
60
68
 
61
69
  const activityScalingMethodState = (_: any): void => {
62
70
  activityScalingMethod.enabled = (activityColumnChoice.value ?? false) &&
63
- DG.Stats.fromColumn(activityColumnChoice.value!, currentDf.filter).min > 0;
71
+ DG.Stats.fromColumn(activityColumnChoice.value!, df.filter).min > 0;
64
72
  activityScalingMethod.fireChanged();
65
73
  };
66
- const activityColumnChoice = ui.columnInput('Activity', currentDf, defaultColumn, activityScalingMethodState);
67
- const clustersColumnChoice = ui.columnInput('Clusters', currentDf, null);
74
+ const activityColumnChoice = ui.columnInput('Activity', df, defaultActivityColumn, activityScalingMethodState);
75
+ const clustersColumnChoice = ui.columnInput('Clusters', df, null);
68
76
  activityColumnChoice.fireChanged();
69
77
  activityScalingMethod.fireChanged();
70
78
 
71
79
  const inputsList = [activityColumnChoice, activityScalingMethod, clustersColumnChoice];
72
80
 
73
81
  const startBtn = ui.button('Launch SAR', async () => {
74
- await startAnalysis(
75
- activityColumnChoice.value, col, clustersColumnChoice.value, currentDf, scaledDf, newScaledColName);
82
+ await startAnalysis(activityColumnChoice.value, col, clustersColumnChoice.value, df, scalingFormula,
83
+ newScaledColName, activityScalingMethod.value ?? 'none', indexes);
76
84
  });
77
85
  startBtn.style.alignSelf = 'center';
78
86
 
79
- const viewer = await currentDf.plot.fromType('WebLogo') as WebLogo;
87
+ const viewer = await df.plot.fromType('WebLogo') as WebLogo;
80
88
  viewer.root.style.setProperty('height', '130px');
81
89
  const logoHost = ui.div();
82
90
  $(logoHost).empty().append(viewer.root);
@@ -92,26 +100,36 @@ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Col
92
100
  );
93
101
  }
94
102
 
95
- export async function startAnalysis(
96
- activityColumn: DG.Column<number> | null, alignedSeqCol: DG.Column<string>, clustersColumn: DG.Column | null,
97
- currentDf: DG.DataFrame, scaledDf: DG.DataFrame, newScaledColName: string): Promise<PeptidesModel | null> {
103
+ export async function startAnalysis(activityColumn: DG.Column<number> | null, peptidesCol: DG.Column<string>,
104
+ clustersColumn: DG.Column | null, currentDf: DG.DataFrame, scaleNum: (x: number) => number, newScaledColName: string,
105
+ scaling: string, indexes: number[]): Promise<PeptidesModel | null> {
98
106
  const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
99
107
  let model = null;
100
108
  if (activityColumn?.type === DG.TYPE.FLOAT) {
101
- const activityColumnName: string = activityColumn.name;
102
- const cloneColList = [alignedSeqCol.name, activityColumnName];
103
- if (clustersColumn)
104
- cloneColList.push(clustersColumn.name);
105
-
109
+ const f = currentDf.filter;
106
110
  //prepare new DF
107
- const newDf = currentDf.clone(currentDf.filter, cloneColList);
108
- const activityCol = newDf.getCol(activityColumnName);
109
- activityCol.name = C.COLUMNS_NAMES.ACTIVITY;
110
- activityCol.semType = C.SEM_TYPES.ACTIVITY;
111
- newDf.getCol(alignedSeqCol.name).name = C.COLUMNS_NAMES.ALIGNED_SEQUENCE;
112
- const activityScaledCol = scaledDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
111
+ const newDf = DG.DataFrame.create(f.trueCount);
112
+ const getIndex = indexes.length !== 0 ? (i: number) : number => indexes[i] : (i: number): number => i;
113
+ let activityCol: DG.Column<number> | null = null;
114
+ for (const col of currentDf.columns.toList()) {
115
+ let virtualCol: DG.Column<any>;
116
+ if (col === activityColumn) {
117
+ virtualCol = newDf.columns.addNewVirtual(
118
+ C.COLUMNS_NAMES.ACTIVITY, (i) => activityColumn.get(getIndex(i)!), DG.TYPE.FLOAT);
119
+ activityCol = virtualCol;
120
+ } else if (col === peptidesCol) {
121
+ virtualCol = newDf.columns.addNewVirtual(
122
+ C.COLUMNS_NAMES.MACROMOLECULE, (i) => peptidesCol.get(getIndex(i)!), DG.TYPE.STRING);
123
+ } else
124
+ virtualCol = newDf.columns.addNewVirtual(col.name, (i) => col.get(getIndex(i)!), col.type as DG.TYPE);
125
+ virtualCol.setTag(C.TAGS.VISIBLE, '0');
126
+ }
127
+ activityCol!.semType = C.SEM_TYPES.ACTIVITY;
128
+ const activityScaledCol = newDf.columns.addNewVirtual(C.COLUMNS_NAMES.ACTIVITY_SCALED, (i) => {
129
+ const val = activityCol!.get(getIndex(i)!);
130
+ return val ? scaleNum(val) : val;
131
+ }, DG.TYPE.FLOAT);
113
132
  activityScaledCol.semType = C.SEM_TYPES.ACTIVITY_SCALED;
114
- newDf.columns.add(activityScaledCol);
115
133
  newDf.name = 'Peptides analysis';
116
134
  newDf.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newScaledColName;
117
135
  if (clustersColumn) {
@@ -119,13 +137,14 @@ export async function startAnalysis(
119
137
  newDf.tags[C.TAGS.CLUSTERS] = C.COLUMNS_NAMES.CLUSTERS;
120
138
  }
121
139
  // newDf.tags[C.PEPTIDES_ANALYSIS] = 'true';
140
+ newDf.tags['scaling'] = scaling;
122
141
 
123
142
  let monomerType = 'HELM_AA';
124
- if (alignedSeqCol.getTag(DG.TAGS.UNITS).toLowerCase() == 'helm') {
125
- const sampleSeq = alignedSeqCol.get(0)!;
143
+ if (peptidesCol.getTag(DG.TAGS.UNITS).toLowerCase() == 'helm') {
144
+ const sampleSeq = peptidesCol.get(0)!;
126
145
  monomerType = sampleSeq.startsWith('PEPTIDE') ? 'HELM_AA' : 'HELM_BASE';
127
146
  } else {
128
- const alphabet = alignedSeqCol.tags[C.TAGS.ALPHABET];
147
+ const alphabet = peptidesCol.tags[C.TAGS.ALPHABET];
129
148
  monomerType = alphabet == 'DNA' || alphabet == 'RNA' ? 'HELM_BASE' : 'HELM_AA';
130
149
  }
131
150
 
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=7770371320b2. Commit 8cac318e.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=916a90d7d48b. Commit ea373bf5.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,11 +229,14 @@ 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=7770371320b2. Commit 8cac318e.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-09-29 14:06:21</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">118.684s</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">101.87s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Evaluation failed: TypeError: Cannot read properties of null (reading 'get')
233
- at __puppeteer_evaluation_script__:17:71
234
- at ExecutionContext._evaluateInternal (/home/runner/work/public/public/packages/Peptides/node_modules/puppeteer/src/common/ExecutionContext.ts:273:13)
235
- at processTicksAndRejections (internal/process/task_queues.js:97:5)
236
- at ExecutionContext.evaluate (/home/runner/work/public/public/packages/Peptides/node_modules/puppeteer/src/common/ExecutionContext.ts:140:12)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:62:11)
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Peptides Test Report. Datagrok version datagrok/datagrok:latest SHA=916a90d7d48b. Commit ea373bf5.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-10-13 13:02:52</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">89.905s</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">73.37s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Failed : 501 : Peptides.Core.Start analysis: simple : Unable to get project asset "getMonomerLib"
233
+ Test result : Failed : 438 : Peptides.Core.Start analysis: сomplex : Unable to get project asset "getMonomerLib"
234
+ Test result : Failed : 431 : Peptides.Core.Save and load project : Unable to get project asset "getMonomerLib"
235
+
236
+ at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:68:20
237
+ at Generator.next (&lt;anonymous&gt;)
238
+ at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:31:58)
239
+ at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:62:11)
237
240
  at Generator.next (&lt;anonymous&gt;)
238
241
  at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/test-node.ts:28:58)
239
242
  at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:40:11
@@ -243,4 +246,31 @@ header {
243
246
  at Object.&lt;anonymous&gt;.__awaiter (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:30:12)
244
247
  at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:38:23)
245
248
  at Promise.then.completed (/home/runner/work/public/public/packages/Peptides/node_modules/jest-circus/build/utils.js:391:28)
246
- at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Peptides package</pre></div></div></div></div></body></html>
249
+ at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Peptides package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:66:11
250
+ at Generator.next (&lt;anonymous&gt;)
251
+ at fulfilled (/home/runner/work/public/public/packages/Peptides/src/__jest__/remote.test.ts:31:58)
252
+ at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Test result : Success : 0 : Peptides.Peptide space.test_table.is_not_empty : OK
253
+ Test result : Success : 6322 : Peptides.Peptide space.PeptideSimilaritySpaceWidget.is_drawing : OK
254
+ Test result : Success : 2 : Peptides.Peptide space.test_deminsionality_reducer : OK
255
+ Test result : Success : 1 : Peptides.Peptide space.test_peptide_similarity_space_viewer : OK
256
+ Test result : Success : 4207 : Peptides.Peptide space.peptide_space.DimensinalityReducer.UMAP.Levenshtein.is_numeric : OK
257
+ Test result : Success : 2954 : Peptides.Peptide space.peptide_space.DimensinalityReducer.UMAP.Jaro-Winkler.is_numeric : OK
258
+ Test result : Success : 3304 : Peptides.Peptide space.peptide_space.DimensinalityReducer.t-SNE.Levenshtein.is_numeric : OK
259
+ Test result : Success : 3696 : Peptides.Peptide space.peptide_space.DimensinalityReducer.t-SNE.Jaro-Winkler.is_numeric : OK
260
+ Test result : Success : 199 : Peptides.Peptide space.peptide_space.DimensinalityReducer.SPE.Levenshtein.is_numeric : OK
261
+ Test result : Success : 803 : Peptides.Peptide space.peptide_space.DimensinalityReducer.SPE.Jaro-Winkler.is_numeric : OK
262
+ Test result : Success : 166 : Peptides.Peptide space.peptide_space.DimensinalityReducer.pSPE.Levenshtein.is_numeric : OK
263
+ Test result : Success : 622 : Peptides.Peptide space.peptide_space.DimensinalityReducer.pSPE.Jaro-Winkler.is_numeric : OK
264
+ Test result : Success : 7452 : Peptides.Peptide space.peptide_space.DimensinalityReducer.OriginalSPE.Levenshtein.is_numeric : OK
265
+ Test result : Success : 8496 : Peptides.Peptide space.peptide_space.DimensinalityReducer.OriginalSPE.Jaro-Winkler.is_numeric : OK
266
+ Test result : Success : 2071 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.UMAP.Levenshtein.is_proper : OK
267
+ Test result : Success : 2746 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.UMAP.Jaro-Winkler.is_proper : OK
268
+ Test result : Success : 3306 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.t-SNE.Levenshtein.is_proper : OK
269
+ Test result : Success : 4189 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.t-SNE.Jaro-Winkler.is_proper : OK
270
+ Test result : Success : 239 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.SPE.Levenshtein.is_proper : OK
271
+ Test result : Success : 732 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.SPE.Jaro-Winkler.is_proper : OK
272
+ Test result : Success : 347 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.pSPE.Levenshtein.is_proper : OK
273
+ Test result : Success : 659 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.pSPE.Jaro-Winkler.is_proper : OK
274
+ Test result : Success : 7587 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.OriginalSPE.Levenshtein.is_proper : OK
275
+ Test result : Success : 8158 : Peptides.Peptide space.peptide_space.PeptideSimilaritySpaceViewer.OriginalSPE.Jaro-Winkler.is_proper : OK
276
+ </pre></div></div></div></div></body></html>