@datagrok/peptides 0.3.0 → 0.5.6

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.
@@ -1,109 +1,204 @@
1
1
  /* Do not change these import lines. Datagrok will import API library in exactly the same manner */
2
- //import * as grok from 'datagrok-api/grok';
3
- //import * as ui from 'datagrok-api/ui';
4
2
  import * as DG from 'datagrok-api/dg';
5
3
 
6
4
  import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
7
- import {assert, transposeMatrix, matrix2DataFrame} from '@datagrok-libraries/utils/src/operations';
8
- import {Vector} from '@datagrok-libraries/utils/src/type_declarations';
5
+ import {assert} from '@datagrok-libraries/utils/src/operations';
6
+ import {Matrix} from '@datagrok-libraries/utils/src/type-declarations';
7
+ import {kendallsTau} from '@datagrok-libraries/statistics/src/correlation-coefficient';
9
8
 
10
9
  /**
11
- * Encodes amino acid sequences into a numeric representation.
10
+ * Converts a Matrix into a DataFrame.
12
11
  *
13
12
  * @export
14
- * @param {DG.Column} col A column containing the sequences.
15
- * @return {DG.DataFrame} The resulting data frame.
13
+ * @param {Matrix} matrix A matrix.
14
+ * @return {DG.DataFrame} The data frame.
16
15
  */
17
- export function calcPositions(col: DG.Column): DG.DataFrame {
18
- const sequences = col.toList().map((v, _) => AlignedSequenceEncoder.clean(v));
19
- const enc = new AlignedSequenceEncoder();
20
- const encSeqs = sequences.map((v) => Vector.from(enc.encode(v)));
21
- const positions = transposeMatrix(encSeqs);
22
- return matrix2DataFrame(positions);
16
+ function matrix2DataFrame(matrix: Matrix): DG.DataFrame {
17
+ return DG.DataFrame.fromColumns(matrix.map((v, i) => DG.Column.fromFloat32Array(`${i+1}`, v)));
23
18
  }
24
19
 
25
20
  /**
26
- * Unfolds a data frame into <category>-<value> format.
21
+ * Encodes sequence into a certain scale.
27
22
  *
28
- * @export
29
- * @param {DG.DataFrame} df A data frame to unfold.
30
- * @return {DG.DataFrame} The resulting data frame.
23
+ * @param {DG.DataFrame} df A data frame containing the sequences.
24
+ * @param {string[]} [positionColumns] If given instructs which columns to consider as sequences containing.
25
+ * @return {DG.DataFrame} The data frame with seqences encoded.
31
26
  */
32
- export function melt(df: DG.DataFrame): DG.DataFrame {
33
- let keys: string[] = [];
34
- const values: Float32Array = new Float32Array(df.columns.length*df.rowCount);
35
- let i = 0;
36
-
37
- for (const c of df.columns.toList()) {
38
- keys = keys.concat(Array<string>(c.length).fill(c.name));
39
- values.set(c.getRawData(), i);
40
- i += df.rowCount;
27
+ function encodeSequences(df: DG.DataFrame, positionColumns?: string[]): DG.DataFrame {
28
+ const [nCols, nRows] = [positionColumns ? positionColumns.length : df.columns.length, df.rowCount];
29
+ const enc = new AlignedSequenceEncoder('WimleyWhite');
30
+ const positions = new Array(nCols).fill(0).map((_) => new Float32Array(nRows));
31
+
32
+ for (let i = 0; i < nCols; ++i) {
33
+ const col: DG.Column = positionColumns ? df.getCol(positionColumns[i]) : df.columns.byIndex(i);
34
+
35
+ for (let j = 0; j < nRows; ++j) {
36
+ const letter = col.get(j);
37
+ positions[i][j] = enc.encodeLettter(letter);
38
+ }
41
39
  }
42
- assert(keys.length == values.length);
43
- return DG.DataFrame.fromColumns([DG.Column.fromStrings('keys', keys), DG.Column.fromFloat32Array('values', values)]);
40
+ const posDF = DG.DataFrame.fromColumns(positions.map((v, i) => DG.Column.fromFloat32Array(df.columns.names()[i], v)));
41
+ return posDF;
44
42
  }
45
43
 
46
- /*export async function calcSpearmanRhoMatrixExt(positions: Matrix): Promise<Matrix> {
47
- const Spearman = require('spearman-rho');
48
- const nItems = positions.length;
49
- const rho = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
44
+ /**
45
+ * Formats an adjacency matrix into <category1>-<category2>-<value> format.
46
+ *
47
+ * @param {DG.DataFrame} adjMatrix A data matrix to deal with.
48
+ * @return {DG.DataFrame} The resulting data frame.
49
+ */
50
+ function createNetwork(adjMatrix: DG.DataFrame): DG.DataFrame {
51
+ const nCols = adjMatrix.columns.length;
52
+ const nRows = adjMatrix.rowCount;
50
53
 
51
- for (let i = 0; i < nItems; ++i) {
52
- for (let j = i+1; j < nItems; ++j) {
53
- rho[i][j] = await(new Spearman(positions[i], positions[j])).calc();
54
- rho[j][i] = rho[i][j];
54
+ assert(nCols == nRows);
55
+
56
+ const pos1: Array<number> = [];
57
+ const pos2: Array<number> = [];
58
+ const weight: Array<number> = [];
59
+
60
+ for (let i = 0; i < nCols; ++i) {
61
+ const c = adjMatrix.columns.byIndex(i);
62
+
63
+ for (let j = i+1; j < nRows; ++j) {
64
+ const r = c.getRawData()[j];
65
+
66
+ if (Math.abs(r) > 0) {
67
+ pos1.push(i+1);
68
+ pos2.push(j+1);
69
+ weight.push(r);
70
+ }
55
71
  }
56
72
  }
57
- return rho;
58
- }*/
73
+
74
+ const pos1Col = DG.Column.fromList('int', 'pos1', pos1);
75
+ const pos2Col = DG.Column.fromList('int', 'pos2', pos2);
76
+ const weightCol = DG.Column.fromList('double', 'weight', weight);
77
+
78
+ return DG.DataFrame.fromColumns([pos1Col, pos2Col, weightCol]);
79
+ }
59
80
 
60
81
  /**
61
- * Calculates Spearman's rho rank correlation coefficient.
82
+ * Calculates Kendall's tau rank correlation matrix.
62
83
  *
63
- * @export
64
84
  * @param {DG.DataFrame} df A data frame to process.
85
+ * @param {number} [alpha=0.05] The significance threshold.
86
+ * @param {number} [rAbsCutoff=0.5] The absolute R cutoff.
65
87
  * @return {DG.DataFrame} The correlation matrix.
66
88
  */
67
- export function calcSpearmanRhoMatrix(df: DG.DataFrame): DG.DataFrame {
89
+ function calcKendallTauMatrix(df: DG.DataFrame, alpha: number = 0.05, rAbsCutoff = 0.5): DG.DataFrame {
68
90
  const nItems = df.columns.length;
69
- const rho = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
91
+ const tau = new Array(nItems).fill(0).map((_) => new Float32Array(nItems).fill(0));
70
92
 
71
93
  for (let i = 0; i < nItems; ++i) {
72
94
  for (let j = i+1; j < nItems; ++j) {
73
- rho[i][j] = df.columns.byIndex(i).stats.spearmanCorr(df.columns.byIndex(j));
74
- rho[j][i] = rho[i][j];
95
+ const res = kendallsTau(df.columns.byIndex(i).getRawData(), df.columns.byIndex(j).getRawData());
96
+ tau[i][j] = (res.prob < alpha) && (Math.abs(res.test) >= rAbsCutoff) ? res.test : 0;
97
+ tau[j][i] = tau[i][j];
98
+ }
99
+ }
100
+ return matrix2DataFrame(tau);
101
+ }
102
+
103
+ /**
104
+ * Calculates a correlation matrix via method chosen.
105
+ *
106
+ * @param {DG.DataFrame} df A data frame.
107
+ * @return {DG.DataFrame} The correlation matrix.
108
+ */
109
+ function calcCorrelationMatrix(df: DG.DataFrame): DG.DataFrame {
110
+ return calcKendallTauMatrix(df);
111
+ }
112
+
113
+ type Weights = {[pos: number]: number};
114
+ type Guide = {[pos: number]: Weights};
115
+
116
+ /**
117
+ * Calculates a dictionary with the keys containing the first correlating positions.
118
+ * Values correspond to a dictionary containing the positions and corresponding R-value
119
+ * which the given position correlating with.
120
+ *
121
+ * @param {DG.DataFrame} network A network to process.
122
+ * @return {Guide} The formatted dictionary.
123
+ */
124
+ function calcGuide(network: DG.DataFrame): Guide {
125
+ assert(network.columns.length == 3);
126
+
127
+ const guide: Guide = {};
128
+ let [pos1Col, pos2Col, weightCol] = Array.from(network.columns);
129
+
130
+ pos1Col = pos1Col.getRawData();
131
+ pos2Col = pos2Col.getRawData();
132
+ weightCol = weightCol.getRawData();
133
+
134
+ function _addWeight(pos1: number, pos2: number, weight: number) {
135
+ if (guide[pos1] == undefined) {
136
+ guide[pos1] = {};
75
137
  }
138
+ guide[pos1][pos2] = weight;
139
+ }
140
+
141
+ for (let i = 0; i < network.rowCount; ++i) {
142
+ const [pos1, pos2, weight] = [pos1Col[i], pos2Col[i], weightCol[i]];
143
+ _addWeight(pos1, pos2, weight);
144
+ _addWeight(pos2, pos1, weight);
76
145
  }
77
- return matrix2DataFrame(rho);
146
+ return guide;
147
+ }
148
+
149
+ function calcCorrelations(df: DG.DataFrame, positionColumns?: string[]): Guide {
150
+ const posDF = encodeSequences(df, positionColumns);
151
+ const ccDF = calcCorrelationMatrix(posDF);
152
+ const nwDF = createNetwork(ccDF);
153
+ const guide = calcGuide(nwDF);
154
+ return guide;
78
155
  }
79
156
 
80
157
  /**
81
- * Creates acorrelation plot and a box plot to perform correlation analysis.
158
+ * Formats correlating positions to place in the corresponding tooltips.
159
+ * Higlights correlating positions' headers.
82
160
  *
83
161
  * @export
84
- * @param {DG.Column} sequencesColumn A column containing amino acid sequences.
85
- * @return {[DG.Viewer, DG.Viewer]} These two plots.
162
+ * @class CorrelationAnalysisVisualizer
86
163
  */
87
- export function correlationAnalysisPlots(sequencesColumn: DG.Column): [DG.Viewer, DG.Viewer] {
88
- const posDF = calcPositions(sequencesColumn);
89
- const cpviewer = DG.Viewer.fromType(
90
- DG.VIEWER.CORR_PLOT,
91
- posDF,
92
- {
93
- 'xColumnNames': posDF.columns.names(),
94
- 'yColumnNames': posDF.columns.names(),
95
- 'correlationType': 'Spearman',
96
- });
97
-
98
- const rhoDF = calcSpearmanRhoMatrix(posDF);
99
- const meltDF = melt(rhoDF);
100
-
101
- const bpviewer = DG.Viewer.fromType(
102
- DG.VIEWER.BOX_PLOT,
103
- meltDF, {
104
- 'categoryColumnName': 'keys',
105
- 'valueColumnName': 'values',
106
- 'statistics': ['min', 'max', 'avg', 'med'],
107
- });
108
- return [cpviewer, bpviewer];
164
+ export class CorrelationAnalysisVisualizer {
165
+ protected guide: Guide;
166
+ protected highlightedColumns: number[];
167
+
168
+ /**
169
+ * Creates an instance of CorrelationAnalysisVisualizer.
170
+ * @param {DG.DataFrame} df A data frame to take sequences from.
171
+ * @param {string[]} positionColumns Optional columns list to take the sequences from.
172
+ * @memberof CorrelationAnalysisVisualizer
173
+ */
174
+ constructor(df: DG.DataFrame, positionColumns: string[]) {
175
+ if (df) {
176
+ this.guide = calcCorrelations(df, positionColumns);
177
+ this.highlightedColumns = Object.keys(this.guide).map((v) => parseInt(v));
178
+ } else {
179
+ throw new Error('Dataframe was not found in the grid.');
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Returns a dictionary with the correlating positions and their R-value.
185
+ *
186
+ * @readonly
187
+ * @type {Guide} The dictionary.
188
+ * @memberof CorrelationAnalysisVisualizer
189
+ */
190
+ get path(): Guide {
191
+ return this.guide;
192
+ }
193
+
194
+ /**
195
+ * Checks if the position column name is found among correlelating ones.
196
+ *
197
+ * @param {string} name The name of the column.
198
+ * @return {boolean} True if the position is correlating with any oter.
199
+ * @memberof CorrelationAnalysisVisualizer
200
+ */
201
+ public isPositionCorrelating(name: string): boolean {
202
+ return this.highlightedColumns.includes(parseInt(name));
203
+ }
109
204
  }
@@ -1,6 +1,4 @@
1
1
  /* Do not change these import lines. Datagrok will import API library in exactly the same manner */
2
- // eslint-disable-next-line no-unused-vars
3
- import * as grok from 'datagrok-api/grok';
4
2
  import * as ui from 'datagrok-api/ui';
5
3
  import * as DG from 'datagrok-api/dg';
6
4
 
@@ -8,16 +6,16 @@ import {getSequenceMolecularWeight} from './molecular-measure';
8
6
  import {AlignedSequenceEncoder} from '@datagrok-libraries/utils/src/sequence-encoder';
9
7
  import {DimensionalityReducer} from '@datagrok-libraries/utils/src/reduce-dimensionality';
10
8
  import {Measurer} from '@datagrok-libraries/utils/src/string-measure';
11
- import {Coordinates} from '@datagrok-libraries/utils/src/type_declarations';
9
+ import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
12
10
 
13
11
  /**
14
- * Creates a worker to perform a dimensionality reduction.
12
+ * A worker to perform dimensionality reduction.
15
13
  *
16
- * @param {any[]} columnData Samples to process.
17
- * @param {string} method Embedding method.
18
- * @param {string} measure Distance metric.
19
- * @param {number} cyclesCount Number of cycles to repeat.
20
- * @return {Promise<unknown>} Promise.
14
+ * @param {any[]} columnData The data to process.
15
+ * @param {string} method A method of dimensionality reduction.
16
+ * @param {string} measure A distance metrics.
17
+ * @param {number} cyclesCount Number of iterations to run.
18
+ * @return {Promise<unknown>} Resulting embedding.
21
19
  */
22
20
  function createDimensinalityReducingWorker(
23
21
  columnData: any[],
@@ -49,7 +47,6 @@ function inferActivityColumnsName(table: DG.DataFrame): string | null {
49
47
  const re = /activity|ic50/i;
50
48
  for (const name of table.columns.names()) {
51
49
  if (name.match(re)) {
52
- console.log(`${name} found.`);
53
50
  return name;
54
51
  }
55
52
  }
@@ -65,6 +62,7 @@ function inferActivityColumnsName(table: DG.DataFrame): string | null {
65
62
  * @param {string} method Embedding method to apply.
66
63
  * @param {string} measure Distance metric.
67
64
  * @param {number} cyclesCount Number of cycles to repeat.
65
+ * @param {(DG.TableView | null)} view View to add scatter plot to
68
66
  * @param {(string | null)} [activityColumnName] Activity containing column to assign it to points radius.
69
67
  * @param {boolean} [zoom=false] Whether to fit view.
70
68
  * @return {Promise<DG.ScatterPlotViewer>} A viewer.
@@ -75,6 +73,7 @@ export async function createPeptideSimilaritySpaceViewer(
75
73
  method: string,
76
74
  measure: string,
77
75
  cyclesCount: number,
76
+ view: DG.TableView | null,
78
77
  activityColumnName?: string | null,
79
78
  zoom: boolean = false,
80
79
  ): Promise<DG.ScatterPlotViewer> {
@@ -110,24 +109,25 @@ export async function createPeptideSimilaritySpaceViewer(
110
109
  // Add new axes.
111
110
  for (const axis of axesNames) {
112
111
  const col = table.col(axis);
112
+ const newCol = edf.getCol(axis);
113
113
 
114
- if (col == null) {
115
- table.columns.insert(edf.getCol(axis));
114
+ if (col != null) {
115
+ for (let i = 0; i < newCol.length; ++i) {
116
+ const v = newCol.get(i);
117
+ table.set(axis, i, v);
118
+ }
116
119
  } else {
117
- table.columns.replace(col, edf.getCol(axis));
120
+ table.columns.insert(newCol);
118
121
  }
119
122
  }
120
- const viewer = DG.Viewer.scatterPlot(table, {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'});
121
-
122
- // Fit view if needed.
123
- /*if (zoom) {
124
- viewer.zoom(
125
- table.getCol('~X').min,
126
- table.getCol('~Y').min,
127
- table.getCol('~X').max,
128
- table.getCol('~Y').max,
129
- );
130
- }*/
123
+
124
+ const viewerOptions = {x: '~X', y: '~Y', color: activityColumnName ?? '~MW', size: '~MW'};
125
+ const viewer = DG.Viewer.scatterPlot(table, viewerOptions);
126
+
127
+ if (view !== null) {
128
+ view.addViewer(viewer);
129
+ }
130
+
131
131
  pi.close();
132
132
  return viewer;
133
133
  }
@@ -147,13 +147,15 @@ export class PeptideSimilaritySpaceWidget {
147
147
  protected availableMethods: string[];
148
148
  protected availableMetrics: string[];
149
149
  protected viewer: HTMLElement;
150
+ view: DG.TableView;
150
151
 
151
152
  /**
152
153
  * Creates an instance of PeptideSimilaritySpaceWidget.
153
154
  * @param {DG.Column} alignedSequencesColumn The column to get amino acid sequences from.
155
+ * @param {DG.TableView} view Current view
154
156
  * @memberof PeptideSimilaritySpaceWidget
155
157
  */
156
- constructor(alignedSequencesColumn: DG.Column) {
158
+ constructor(alignedSequencesColumn: DG.Column, view: DG.TableView) {
157
159
  this.availableMethods = DimensionalityReducer.availableMethods;
158
160
  this.availableMetrics = Measurer.availableMeasures;
159
161
  this.method = this.availableMethods[0];
@@ -161,6 +163,7 @@ export class PeptideSimilaritySpaceWidget {
161
163
  this.currentDf = alignedSequencesColumn.dataFrame;
162
164
  this.alignedSequencesColumn = alignedSequencesColumn;
163
165
  this.viewer = ui.div([]);
166
+ this.view = view;
164
167
  }
165
168
 
166
169
  /**
@@ -177,6 +180,7 @@ export class PeptideSimilaritySpaceWidget {
177
180
  this.metrics,
178
181
  this.cycles,
179
182
  null,
183
+ null,
180
184
  true,
181
185
  );
182
186
  viewer.root.style.width = 'auto';
@@ -1,5 +1,13 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
+ /**
4
+ * Split aligned sequence string into separate parts containing amino acid residues.
5
+ *
6
+ * @export
7
+ * @param {DG.Column} peptideColumn Column containing aligned sequences.
8
+ * @param {boolean} [filter=true] Filter out columns with all the same residues.
9
+ * @return {[DG.DataFrame, number[]]} DataFrame containing split sequence and a list of invalid indexes.
10
+ */
3
11
  export function splitAlignedPeptides(peptideColumn: DG.Column, filter: boolean = true): [DG.DataFrame, number[]] {
4
12
  const splitPeptidesArray: string[][] = [];
5
13
  let currentSplitPeptide: string[];
@@ -45,7 +53,6 @@ export function splitAlignedPeptides(peptideColumn: DG.Column, filter: boolean =
45
53
  columnNames.push('C-terminal');
46
54
 
47
55
  // filter out the columns with the same values
48
-
49
56
  if (filter) {
50
57
  splitColumns = splitColumns.filter((positionArray, index) => {
51
58
  const isRetained = new Set(positionArray).size > 1;
@@ -7,6 +7,13 @@ import * as logojs from 'logojs-react';
7
7
  import {splitAlignedPeptides} from '../utils/split-aligned';
8
8
  import {ChemPalette} from '../utils/chem-palette';
9
9
 
10
+ /**
11
+ * Logo viewer.
12
+ *
13
+ * @export
14
+ * @class Logo
15
+ * @extends {DG.JsViewer}
16
+ */
10
17
  export class Logo extends DG.JsViewer {
11
18
  initialized: boolean;
12
19
  option: any;
@@ -18,6 +25,11 @@ export class Logo extends DG.JsViewer {
18
25
  LET_COLORS: Array<any>;
19
26
  target: DG.DataFrame | undefined | null;
20
27
 
28
+ /**
29
+ * Creates an instance of Logo.
30
+ *
31
+ * @memberof Logo
32
+ */
21
33
  constructor() {
22
34
  super();
23
35
  this.initialized = false;
@@ -59,9 +71,13 @@ export class Logo extends DG.JsViewer {
59
71
  ];
60
72
  }
61
73
 
74
+ /**
75
+ * Initializer function.
76
+ *
77
+ * @memberof Logo
78
+ */
62
79
  init() {
63
80
  this.initialized = true;
64
- // this.reactHost = ui.div([]);
65
81
  console.log('INIT');
66
82
  this.target = this.dataFrame;
67
83
  [this.splitted] = splitAlignedPeptides(this.dataFrame!.columns.bySemType(this.colSemType));
@@ -70,6 +86,11 @@ export class Logo extends DG.JsViewer {
70
86
  this.root.style.maxHeight = '200px';
71
87
  }
72
88
 
89
+ /**
90
+ * Function to execute when the table is attached.
91
+ *
92
+ * @memberof Logo
93
+ */
73
94
  onTableAttached() {
74
95
  if (typeof this.dataFrame !== 'undefined') {
75
96
  if (!this.initialized) {
@@ -84,16 +105,32 @@ export class Logo extends DG.JsViewer {
84
105
  this.render();
85
106
  }
86
107
 
108
+ /**
109
+ * Function that is executed when the viewer is detached.
110
+ *
111
+ * @memberof Logo
112
+ */
87
113
  detach() {
88
114
  this.subs.forEach((sub) => sub.unsubscribe());
89
115
  }
90
116
 
117
+ /**
118
+ * Function that is executed when the viewer property is changed.
119
+ *
120
+ * @param {DG.Property} property
121
+ * @memberof Logo
122
+ */
91
123
  onPropertyChanged(property: DG.Property) {
92
124
  super.onPropertyChanged(property);
93
125
 
94
126
  this.render();
95
127
  }
96
128
 
129
+ /**
130
+ * Function that renders the viewer.
131
+ *
132
+ * @memberof Logo
133
+ */
97
134
  async render() {
98
135
  const bits = this.dataFrame!.selection;
99
136
  let selected = false;
@@ -111,18 +148,24 @@ export class Logo extends DG.JsViewer {
111
148
 
112
149
  if (typeof this.dataFrame !== 'undefined') {
113
150
  this.findLogo();
114
-
115
- // if (this.reactHost !== null) {
116
- // this.root.appendChild(this.reactHost);
117
- // }
118
151
  }
119
152
  }
120
153
 
154
+ /**
155
+ * Create logo.
156
+ *
157
+ * @memberof Logo
158
+ */
121
159
  async findLogo() {
122
160
  this.getInfoFromDf();
123
161
  logojs.embedProteinLogo(this.root, {alphabet: this.LET_COLORS, ppm: this.ppm});
124
162
  }
125
163
 
164
+ /**
165
+ * Retrieves information for building logo from the dataframe.
166
+ *
167
+ * @memberof Logo
168
+ */
126
169
  getInfoFromDf() {
127
170
  let index: number = 0;
128
171
  this.ppm = [];
@@ -1,15 +1,22 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
3
  import {describe} from '../describe';
4
- import { Subject } from 'rxjs';
4
+ import {Subject} from 'rxjs';
5
5
 
6
+ /**
7
+ * Model class for SAR viewers that retrieves and stores data.
8
+ *
9
+ * @class SARViewerModel
10
+ */
6
11
  class SARViewerModel {
7
12
  private viewerGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
8
13
  private viewerVGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
9
14
  private statsDf: Subject<DG.DataFrame> = new Subject<DG.DataFrame>();
10
- public viewerGrid$ = this.viewerGrid.asObservable();
11
- public viewerVGrid$ = this.viewerVGrid.asObservable();
12
- public statsDf$ = this.statsDf.asObservable();
15
+ private groupMapping: Subject<{[key: string]: string}> = new Subject<{[key: string]: string}>();
16
+ public viewerGrid$;
17
+ public viewerVGrid$;
18
+ public statsDf$;
19
+ public groupMapping$;
13
20
  private dataFrame: DG.DataFrame | null;
14
21
  private activityColumn: string | null;
15
22
  private activityScaling: string | null;
@@ -17,7 +24,13 @@ class SARViewerModel {
17
24
  private twoColorMode: boolean | null;
18
25
  private initialBitset: DG.BitSet | null;
19
26
  private isUpdating = false;
27
+ grouping: boolean;
20
28
 
29
+ /**
30
+ * Creates an instance of SARViewerModel.
31
+ *
32
+ * @memberof SARViewerModel
33
+ */
21
34
  constructor() {
22
35
  this.dataFrame = null;
23
36
  this.activityColumn = null;
@@ -25,39 +38,66 @@ class SARViewerModel {
25
38
  this.sourceGrid = null;
26
39
  this.twoColorMode = null;
27
40
  this.initialBitset = null;
41
+ this.grouping = false;
42
+ this.viewerGrid$ = this.viewerGrid.asObservable();
43
+ this.viewerVGrid$ = this.viewerVGrid.asObservable();
44
+ this.statsDf$ = this.statsDf.asObservable();
45
+ this.groupMapping$ = this.groupMapping.asObservable();
28
46
  }
29
47
 
48
+ /**
49
+ * Updates data with using specified parameters.
50
+ *
51
+ * @param {DG.DataFrame} df Working table.
52
+ * @param {string} activityCol Activity column name.
53
+ * @param {string} activityScaling Activity scaling method.
54
+ * @param {DG.Grid} sourceGrid Working table grid.
55
+ * @param {boolean} twoColorMode Bidirectional analysis enabled.
56
+ * @param {(DG.BitSet | null)} initialBitset Initial bitset.
57
+ * @param {boolean} grouping Grouping enabled.
58
+ * @memberof SARViewerModel
59
+ */
30
60
  async updateData(
31
- df: DG.DataFrame,
32
- activityCol: string,
33
- activityScaling: string,
34
- sourceGrid: DG.Grid,
35
- twoColorMode: boolean,
36
- initialBitset: DG.BitSet | null,
37
- ) {
61
+ df: DG.DataFrame,
62
+ activityCol: string,
63
+ activityScaling: string,
64
+ sourceGrid: DG.Grid,
65
+ twoColorMode: boolean,
66
+ initialBitset: DG.BitSet | null,
67
+ grouping: boolean,
68
+ ) {
38
69
  this.dataFrame = df;
39
70
  this.activityColumn = activityCol;
40
71
  this.activityScaling = activityScaling;
41
72
  this.sourceGrid = sourceGrid;
42
73
  this.twoColorMode = twoColorMode;
43
74
  this.initialBitset = initialBitset;
75
+ this.grouping = grouping;
44
76
  await this.updateDefault();
45
77
  }
46
78
 
79
+ /**
80
+ * Update data using current parameters.
81
+ *
82
+ * @memberof SARViewerModel
83
+ */
47
84
  async updateDefault() {
48
- if (this.dataFrame && this.activityColumn && this.activityScaling && this.sourceGrid && this.twoColorMode !== null && !this.isUpdating) {
85
+ if (
86
+ this.dataFrame && this.activityColumn && this.activityScaling &&
87
+ this.sourceGrid && this.twoColorMode !== null && !this.isUpdating
88
+ ) {
49
89
  this.isUpdating = true;
50
- const [viewerGrid, viewerVGrid, statsDf] = await describe(
90
+ const [viewerGrid, viewerVGrid, statsDf, groupMapping] = await describe(
51
91
  this.dataFrame, this.activityColumn, this.activityScaling,
52
- this.sourceGrid, this.twoColorMode, this.initialBitset
92
+ this.sourceGrid, this.twoColorMode, this.initialBitset, this.grouping,
53
93
  );
54
94
  this.viewerGrid.next(viewerGrid);
55
95
  this.viewerVGrid.next(viewerVGrid);
56
96
  this.statsDf.next(statsDf);
97
+ this.groupMapping.next(groupMapping);
57
98
  this.isUpdating = false;
58
99
  }
59
100
  }
60
101
  }
61
102
 
62
- export let model = new SARViewerModel();
63
-
103
+ export const model = new SARViewerModel();