oncoprintjs 6.0.3 → 6.0.4

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,8 +1,10 @@
1
1
  /// <reference types="jquery" />
2
2
  /// <reference types="jstree" />
3
+ import CachedProperty from './CachedProperty';
3
4
  import { RuleSet, RuleSetParams, RuleWithId } from './oncoprintruleset';
4
5
  import { InitParams } from './oncoprint';
5
6
  import { ComputedShapeParams } from './oncoprintshape';
7
+ import { OncoprintGapConfig } from './oncoprintwebglcellview';
6
8
  export declare type ColumnId = string;
7
9
  export declare type ColumnIndex = number;
8
10
  export declare type TrackId = number;
@@ -49,6 +51,7 @@ export declare type CustomTrackOption = {
49
51
  onClick?: (id: TrackId) => void;
50
52
  weight?: string;
51
53
  disabled?: boolean;
54
+ gapLabelsFn?: (model: OncoprintModel) => OncoprintGapConfig[];
52
55
  };
53
56
  export declare type CustomTrackGroupOption = {
54
57
  label?: string;
@@ -70,6 +73,7 @@ export declare type UserTrackSpec<D> = {
70
73
  onClickRemoveInTrackMenu?: (track_id: TrackId) => void;
71
74
  label?: string;
72
75
  sublabel?: string;
76
+ gapLabelFn?: (model: OncoprintModel) => string[];
73
77
  html_label?: string;
74
78
  track_label_color?: string;
75
79
  track_label_circle_color?: string;
@@ -143,6 +147,9 @@ export declare type ColumnProp<T> = {
143
147
  export declare type ColumnIdSet = {
144
148
  [columnId: string]: any;
145
149
  };
150
+ export declare type OncoprintDataGroupsByTrackId<T> = Record<string, OncoprintDataGroups<T>[]>;
151
+ export declare type OncoprintDataGroups<T> = OncoprintDataGroup<T>[];
152
+ export declare type OncoprintDataGroup<T> = T[];
146
153
  export default class OncoprintModel {
147
154
  private sort_config;
148
155
  rendering_suppressed_depth: number;
@@ -224,7 +231,8 @@ export default class OncoprintModel {
224
231
  private zoomed_column_left;
225
232
  private column_left_no_padding;
226
233
  private precomputed_comparator;
227
- private ids_after_a_gap;
234
+ ids_after_a_gap: CachedProperty<ColumnIdSet>;
235
+ data_groups: CachedProperty<OncoprintDataGroupsByTrackId<TrackProp<ColumnProp<Datum>>>>;
228
236
  private column_indexes_after_a_gap;
229
237
  private track_groups;
230
238
  private unclustered_track_group_order?;
@@ -328,6 +336,7 @@ export default class OncoprintModel {
328
336
  getZoomedColumnLeft(id: ColumnId): number;
329
337
  getOncoprintHeight(base?: boolean): number;
330
338
  getOncoprintWidth(base?: boolean): number;
339
+ showGaps(): boolean;
331
340
  getOncoprintWidthNoColumnPaddingNoGaps(): number;
332
341
  getColumnLabels(): ColumnProp<ColumnLabel>;
333
342
  setColumnLabels(labels: ColumnProp<ColumnLabel>): void;
@@ -372,6 +381,7 @@ export default class OncoprintModel {
372
381
  getLastExpansion(track_id: TrackId): number;
373
382
  getTrackCustomOptions(track_id: TrackId): CustomTrackOption[];
374
383
  setTrackCustomOptions(track_id: TrackId, options: CustomTrackOption[] | undefined): void;
384
+ getGapOffsets(): any;
375
385
  setTrackInfoTooltip(track_id: TrackId, $tooltip_elt: JQuery | undefined): void;
376
386
  $getTrackInfoTooltip(track_id: TrackId): JQuery<HTMLElement>;
377
387
  getRuleSet(track_id: TrackId): RuleSet;
@@ -4,6 +4,15 @@ import OncoprintModel, { ColumnId, TrackId, TrackProp } from './oncoprintmodel';
4
4
  import OncoprintToolTip from './oncoprinttooltip';
5
5
  import { CellClickCallback, CellMouseOverCallback } from './oncoprint';
6
6
  declare type ColorBank = number[];
7
+ declare type OncoprintGap = {
8
+ origin_x: number;
9
+ origin_y: number;
10
+ data: OncoprintGapConfig;
11
+ };
12
+ export declare type OncoprintGapConfig = {
13
+ labelFormatter: () => string;
14
+ tooltipFormatter: () => string;
15
+ };
7
16
  export declare type OncoprintWebGLContext = WebGLRenderingContext & {
8
17
  viewportWidth: number;
9
18
  viewportHeight: number;
@@ -39,6 +48,7 @@ export default class OncoprintWebGLCellView {
39
48
  private $container;
40
49
  private $canvas;
41
50
  private $overlay_canvas;
51
+ private $gap_canvas;
42
52
  private $column_label_canvas;
43
53
  private $dummy_scroll_div_contents;
44
54
  private tooltip;
@@ -51,6 +61,7 @@ export default class OncoprintWebGLCellView {
51
61
  visible_area_width: number;
52
62
  private mouseMoveHandler;
53
63
  private ctx;
64
+ private gap_ctx;
54
65
  private ext;
55
66
  private overlay_ctx;
56
67
  private column_label_ctx;
@@ -78,8 +89,10 @@ export default class OncoprintWebGLCellView {
78
89
  private is_buffer_empty;
79
90
  private color_texture;
80
91
  private id_to_first_vertex_index;
81
- constructor($container: JQuery, $canvas: JQuery<HTMLCanvasElement>, $overlay_canvas: JQuery<HTMLCanvasElement>, $column_label_canvas: JQuery<HTMLCanvasElement>, $dummy_scroll_div_contents: JQuery, model: OncoprintModel, tooltip: OncoprintToolTip, highlight_area_callback: undefined | ((left: number, right: number) => void), cell_over_callback: CellMouseOverCallback, cell_click_callback: CellClickCallback);
92
+ constructor($container: JQuery, $canvas: JQuery<HTMLCanvasElement>, $overlay_canvas: JQuery<HTMLCanvasElement>, $gap_canvas: JQuery<HTMLCanvasElement>, $column_label_canvas: JQuery<HTMLCanvasElement>, $dummy_scroll_div_contents: JQuery, model: OncoprintModel, tooltip: OncoprintToolTip, highlight_area_callback: undefined | ((left: number, right: number) => void), cell_over_callback: CellMouseOverCallback, cell_click_callback: CellClickCallback);
93
+ private drawGapLabel;
82
94
  private getNewCanvas;
95
+ private getGapContext;
83
96
  private getWebGLCanvasContext;
84
97
  private createShaderProgram;
85
98
  private createShader;
@@ -94,6 +107,8 @@ export default class OncoprintWebGLCellView {
94
107
  private getColumnIndexesAfterAGap;
95
108
  private setUpShaders;
96
109
  private resizeAndClear;
110
+ gapTooltipTargets: OncoprintGap[];
111
+ hoveredGap: OncoprintGap;
97
112
  private renderAllTracks;
98
113
  private static getColumnLabelsFontSize;
99
114
  private prepareContextForColumnLabelText;
@@ -162,6 +177,7 @@ export default class OncoprintWebGLCellView {
162
177
  width: number;
163
178
  height: number;
164
179
  };
180
+ getGaps(model: OncoprintModel, track_id: number): OncoprintGapConfig[];
165
181
  toSVGGroup(model: OncoprintModel, offset_x: number, offset_y: number): SVGGElement;
166
182
  destroy(): void;
167
183
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oncoprintjs",
3
- "version": "6.0.3",
3
+ "version": "6.0.4",
4
4
  "description": "A data visualization for cancer genomic data.",
5
5
  "types": "./dist/js/oncoprint.d.ts",
6
6
  "main": "dist/index.js",
@@ -60,5 +60,5 @@
60
60
  "tayden-clusterfck": "^0.7.0",
61
61
  "typescript": "4.0.3"
62
62
  },
63
- "gitHead": "faeca13017380790ba67cacc87bd4fc4ce38fe41"
63
+ "gitHead": "00743bcfb9d752deabdcb1e8235cdb9cc0feb7c5"
64
64
  }
package/src/index.tsx CHANGED
@@ -9,5 +9,6 @@ export {
9
9
  } from './js/oncoprint';
10
10
 
11
11
  export * from './js/oncoprintruleset';
12
+ export { default as OncoprintModel } from './js/oncoprintmodel';
12
13
  export * from './js/oncoprintmodel';
13
14
  export { default as shapeToSvg } from './js/oncoprintshapetosvg';
@@ -192,6 +192,11 @@ export default class Oncoprint {
192
192
  .css({ position: 'absolute', top: '0px', left: '0px' })
193
193
  .addClass('noselect') as JQuery<HTMLCanvasElement>;
194
194
 
195
+ const $gap_canvas = $('<canvas></canvas>')
196
+ .attr({ width: '0px', height: '0px' })
197
+ .css({ position: 'absolute', top: '0px', left: '0px' })
198
+ .addClass('noselect gap_canvas') as JQuery<HTMLCanvasElement>;
199
+
195
200
  const $dummy_scroll_div = $('<div>')
196
201
  .css({
197
202
  position: 'absolute',
@@ -270,6 +275,7 @@ export default class Oncoprint {
270
275
  $minimap_div.appendTo($ctr);
271
276
 
272
277
  $cell_canvas.appendTo($cell_div);
278
+ $gap_canvas.appendTo($cell_div);
273
279
  $cell_overlay_canvas.appendTo($cell_div);
274
280
  $column_label_canvas.appendTo($cell_div); // column labels should show above the overlay canvas because the text should show over the highlights
275
281
  $dummy_scroll_div.appendTo($cell_div);
@@ -300,6 +306,7 @@ export default class Oncoprint {
300
306
  $cell_div,
301
307
  $cell_canvas,
302
308
  $cell_overlay_canvas,
309
+ $gap_canvas,
303
310
  $column_label_canvas,
304
311
  $dummy_scroll_div_contents,
305
312
  this.model,
@@ -756,6 +763,7 @@ export default class Oncoprint {
756
763
  if (this.webgl_unavailable || this.destroyed) {
757
764
  return [];
758
765
  }
766
+
759
767
  // Update model
760
768
  const track_ids: TrackId[] = [];
761
769
  const library_params_list = (params_list as LibraryTrackSpec<
@@ -19,6 +19,7 @@ import { ComputedShapeParams } from './oncoprintshape';
19
19
  import { CaseItem, EntityItem } from './workers/clustering-worker';
20
20
  import PrecomputedComparator from './precomputedcomparator';
21
21
  import { calculateHeaderTops, calculateTrackTops } from './modelutils';
22
+ import { OncoprintGapConfig } from './oncoprintwebglcellview';
22
23
 
23
24
  export type ColumnId = string;
24
25
  export type ColumnIndex = number;
@@ -68,6 +69,7 @@ export type CustomTrackOption = {
68
69
  onClick?: (id: TrackId) => void;
69
70
  weight?: string;
70
71
  disabled?: boolean;
72
+ gapLabelsFn?: (model: OncoprintModel) => OncoprintGapConfig[];
71
73
  };
72
74
  export type CustomTrackGroupOption = {
73
75
  label?: string;
@@ -89,6 +91,7 @@ export type UserTrackSpec<D> = {
89
91
  onClickRemoveInTrackMenu?: (track_id: TrackId) => void;
90
92
  label?: string;
91
93
  sublabel?: string;
94
+ gapLabelFn?: (model: OncoprintModel) => string[];
92
95
  html_label?: string;
93
96
  track_label_color?: string;
94
97
  track_label_circle_color?: string;
@@ -235,6 +238,15 @@ export type TrackGroupProp<T> = { [trackGroupIndex: number]: T };
235
238
  export type ColumnProp<T> = { [columnId: string]: T };
236
239
  export type ColumnIdSet = { [columnId: string]: any };
237
240
 
241
+ export type OncoprintDataGroupsByTrackId<T> = Record<
242
+ string,
243
+ OncoprintDataGroups<T>[]
244
+ >;
245
+
246
+ export type OncoprintDataGroups<T> = OncoprintDataGroup<T>[];
247
+
248
+ export type OncoprintDataGroup<T> = T[];
249
+
238
250
  export default class OncoprintModel {
239
251
  // Global properties
240
252
  private sort_config: SortConfig;
@@ -333,7 +345,12 @@ export default class OncoprintModel {
333
345
  private precomputed_comparator: CachedProperty<
334
346
  TrackProp<PrecomputedComparator<Datum>>
335
347
  >;
336
- private ids_after_a_gap: CachedProperty<ColumnIdSet>;
348
+ public ids_after_a_gap: CachedProperty<ColumnIdSet>;
349
+
350
+ public data_groups: CachedProperty<
351
+ OncoprintDataGroupsByTrackId<TrackProp<ColumnProp<Datum>>>
352
+ >;
353
+
337
354
  private column_indexes_after_a_gap: CachedProperty<number[]>;
338
355
 
339
356
  private track_groups: TrackGroup[];
@@ -571,6 +588,61 @@ export default class OncoprintModel {
571
588
 
572
589
  return gapIds;
573
590
  });
591
+
592
+ this.data_groups = new CachedProperty({}, function(
593
+ model: OncoprintModel
594
+ ) {
595
+ // multiple tracks can have gaps
596
+ // the groups will be segemented heirarchically
597
+ const trackIdsWithGaps = model
598
+ .getTracks()
599
+ .filter(trackId => model.getTrackShowGaps(trackId));
600
+
601
+ const data_groups = _.reduce(
602
+ model.track_label,
603
+ (
604
+ agg: OncoprintDataGroupsByTrackId<
605
+ TrackProp<ColumnProp<Datum>>
606
+ >,
607
+ label,
608
+ trackId: number
609
+ ) => {
610
+ // key the data by the datum UID
611
+ const keyedData = _.keyBy(
612
+ model.track_data[trackId],
613
+ m => m.uid
614
+ );
615
+ const groups = trackIdsWithGaps.map(id => {
616
+ // we need the datum in sorted order
617
+ const data = model.id_order.map(d => keyedData[d]);
618
+
619
+ const indexesAfterGap = model.column_indexes_after_a_gap.get();
620
+
621
+ // the indexes come AFTER a gap, so we need to include zero up front
622
+ // in order to get initial slice of data
623
+ const groupStartIndexes = [0, ...indexesAfterGap];
624
+
625
+ // using the group start indexes, slice the id data into corresponding groups
626
+ return groupStartIndexes.map((n, i) => {
627
+ if (i === groupStartIndexes.length - 1) {
628
+ // we're at last one, so last group
629
+ return data.slice(n);
630
+ } else {
631
+ return data.slice(n, groupStartIndexes[i + 1]);
632
+ }
633
+ });
634
+ });
635
+
636
+ agg[label.trim()] = groups;
637
+
638
+ return agg;
639
+ },
640
+ {}
641
+ );
642
+
643
+ return data_groups;
644
+ });
645
+
574
646
  this.visible_id_order.addBoundProperty(this.ids_after_a_gap);
575
647
  this.precomputed_comparator.addBoundProperty(this.ids_after_a_gap);
576
648
 
@@ -1070,7 +1142,11 @@ export default class OncoprintModel {
1070
1142
  }
1071
1143
 
1072
1144
  public getGapSize() {
1073
- return this.getCellWidth(true);
1145
+ if (this.showGaps()) {
1146
+ return 50; // this creates enough space for 3 digit percentage
1147
+ } else {
1148
+ return this.getCellWidth(true);
1149
+ }
1074
1150
  }
1075
1151
 
1076
1152
  public getCellWidth(base?: boolean) {
@@ -1804,7 +1880,16 @@ export default class OncoprintModel {
1804
1880
  const lastIdLeft = base
1805
1881
  ? this.getColumnLeft(lastId)
1806
1882
  : this.getZoomedColumnLeft(lastId);
1807
- return lastIdLeft + this.getCellWidth(base) + 1; // this fixes some edge case issues with scrolling
1883
+
1884
+ // when gaps are showing, we need to add space at the end of the
1885
+ // oncoprint to accomodate the label
1886
+ const lastGap = this.showGaps() ? this.getGapSize() : 0;
1887
+
1888
+ return lastIdLeft + this.getCellWidth(base) + lastGap + 1; // this fixes some edge case issues with scrolling
1889
+ }
1890
+
1891
+ public showGaps() {
1892
+ return _.some(this.track_show_gaps);
1808
1893
  }
1809
1894
 
1810
1895
  public getOncoprintWidthNoColumnPaddingNoGaps() {
@@ -2032,6 +2117,28 @@ export default class OncoprintModel {
2032
2117
  this.track_custom_options[track_id] = options;
2033
2118
  }
2034
2119
 
2120
+ // get the pixel offset (from the grid origin) for the gaps based
2121
+ public getGapOffsets(): any {
2122
+ const offsets = _(this.ids_after_a_gap.get())
2123
+ .keys()
2124
+ .map(num => this.getZoomedColumnLeft(num))
2125
+ .sort((a, b) => a - b)
2126
+ .value();
2127
+
2128
+ // we only want to include this if gaps are on
2129
+ if (this.showGaps) {
2130
+ const last =
2131
+ this.getZoomedColumnLeft(
2132
+ this.id_order[this.id_order.length - 1]
2133
+ ) +
2134
+ this.getGapSize() +
2135
+ this.cell_width +
2136
+ this.cell_padding;
2137
+ offsets.push(last);
2138
+ }
2139
+ return offsets;
2140
+ }
2141
+
2035
2142
  public setTrackInfoTooltip(
2036
2143
  track_id: TrackId,
2037
2144
  $tooltip_elt: JQuery | undefined
@@ -2,6 +2,7 @@ import svgfactory from './svgfactory';
2
2
  import $ from 'jquery';
3
3
  import OncoprintToolTip from './oncoprinttooltip';
4
4
  import OncoprintModel from './oncoprintmodel';
5
+ import { isNumber } from 'lodash';
5
6
 
6
7
  export default class OncoprintTrackInfoView {
7
8
  private $ctr: JQuery;
@@ -25,7 +26,7 @@ export default class OncoprintTrackInfoView {
25
26
  })
26
27
  .appendTo(this.$div);
27
28
  this.$text_ctr = $('<div></div>')
28
- .css({ position: 'absolute' })
29
+ .css({ position: 'absolute', overflow: 'visible', width: '100%' })
29
30
  .appendTo(this.$ctr);
30
31
  }
31
32
 
@@ -68,13 +69,29 @@ export default class OncoprintTrackInfoView {
68
69
  'font-family': self.font_family,
69
70
  'font-weight': self.font_weight,
70
71
  'font-size': font_size,
72
+ right: '11px',
71
73
  })
72
74
  .addClass('noselect');
73
75
  const text = model.getTrackInfo(tracks[i]);
74
76
  if (!text) {
75
77
  return;
76
78
  }
77
- $new_label.text(text);
79
+
80
+ const float = parseFloat(text);
81
+ let formattedPercent = '';
82
+
83
+ if (isNaN(float)) {
84
+ formattedPercent = 'N/P';
85
+ } else if (isNumber(float)) {
86
+ formattedPercent =
87
+ float < 1 && float > 0
88
+ ? '<1%'
89
+ : Math.round(float) + '%';
90
+ } else {
91
+ // do nothing
92
+ }
93
+
94
+ $new_label.text(formattedPercent);
78
95
  $new_label.appendTo(self.$text_ctr);
79
96
  self.$label_elts.push($new_label);
80
97
  setTimeout(function() {
@@ -206,22 +206,24 @@ export default class OncoprintTrackOptionsView {
206
206
  .addClass(SEPARATOR_CLASS);
207
207
  }
208
208
 
209
+ // 11/2/2023 we are removing sort arrow
210
+ // leaving commented out if it needs to be restored based on complaint
209
211
  private static renderSortArrow(
210
212
  $sortarrow: JQuery,
211
213
  model: OncoprintModel,
212
214
  track_id: TrackId
213
215
  ) {
214
- let sortarrow_char = '';
215
- if (model.isTrackSortDirectionChangeable(track_id)) {
216
- sortarrow_char = {
217
- '1':
218
- '<i class="fa fa-signal" aria-hidden="true" title="Sorted ascending"></i>',
219
- '-1':
220
- '<i class="fa fa-signal" style="transform: scaleX(-1);" aria-hidden="true" title="Sorted descending"></i>',
221
- '0': '',
222
- }[model.getTrackSortDirection(track_id)];
223
- }
224
- $sortarrow.html(sortarrow_char);
216
+ // let sortarrow_char = '';
217
+ // if (model.isTrackSortDirectionChangeable(track_id)) {
218
+ // sortarrow_char = {
219
+ // '1':
220
+ // '<i class="fa fa-signal" aria-hidden="true" title="Sorted ascending"></i>',
221
+ // '-1':
222
+ // '<i class="fa fa-signal" style="transform: scaleX(-1);" aria-hidden="true" title="Sorted descending"></i>',
223
+ // '0': '',
224
+ // }[model.getTrackSortDirection(track_id)];
225
+ // }
226
+ // $sortarrow.html(sortarrow_char);
225
227
  }
226
228
 
227
229
  private renderTrackOptions(