aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Charles Nicholson <nicholsonc@google.com>2016-10-17 07:06:26 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2016-10-17 08:19:00 -0700
commit57174f3e6d4de4ced3c6df1ed073637c64e589fc (patch)
treee064b60a978e23b3e8c51473e2d455f493df5e2e
parent64d29a95e41113d4abf7e64cd1f6d8cdb01bc018 (diff)
Add ProjectorScatterPlotAdapter, which turns 'hover, selected, neighbors' into
color / scale / opacity / label arrays to power the scatter plot. I started moving the trace code to be array-driven like the rest of the render attributes, but it turns out that the easiest way to do that is to rewrite the trace visualizer as a generic "LineSegmentVisualizer" that accumulates all line segments into a single render call. Reverted but coming soon. Change: 136351181
-rw-r--r--tensorflow/tensorboard/components/vz-projector/projectorScatterPlotAdapter.ts215
-rw-r--r--tensorflow/tensorboard/components/vz-projector/renderContext.ts9
-rw-r--r--tensorflow/tensorboard/components/vz-projector/scatterPlot.ts4
-rw-r--r--tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer.ts2
-rw-r--r--tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer3DLabels.ts20
-rw-r--r--tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerAxes.ts2
-rw-r--r--tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerSprites.ts12
-rw-r--r--tensorflow/tensorboard/components/vz-projector/vz-projector.ts226
8 files changed, 263 insertions, 227 deletions
diff --git a/tensorflow/tensorboard/components/vz-projector/projectorScatterPlotAdapter.ts b/tensorflow/tensorboard/components/vz-projector/projectorScatterPlotAdapter.ts
new file mode 100644
index 0000000000..1f5576ec17
--- /dev/null
+++ b/tensorflow/tensorboard/components/vz-projector/projectorScatterPlotAdapter.ts
@@ -0,0 +1,215 @@
+/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+import {DataSet} from './data';
+import {NearestEntry} from './knn';
+import {LabelRenderParams} from './renderContext';
+
+const LABEL_FONT_SIZE = 10;
+const LABEL_SCALE_DEFAULT = 1.0;
+const LABEL_SCALE_LARGE = 1.7;
+const LABEL_FILL_COLOR = 0x000000;
+const LABEL_STROKE_COLOR = 0xFFFFFF;
+
+const POINT_COLOR_UNSELECTED = 0x888888;
+const POINT_COLOR_NO_SELECTION = 0x7575D9;
+const POINT_COLOR_SELECTED = 0xFA6666;
+const POINT_COLOR_HOVER = 0x760B4F;
+
+const POINT_SCALE_DEFAULT = 1.0;
+const POINT_SCALE_SELECTED = 1.2;
+const POINT_SCALE_NEIGHBOR = 1.2;
+const POINT_SCALE_HOVER = 1.2;
+
+const LABELS_3D_COLOR_UNSELECTED = 0xFFFFFF;
+const LABELS_3D_COLOR_NO_SELECTION = 0xFFFFFF;
+
+/**
+ * Interprets projector events and assembes the arrays and commands necessary
+ * to use the ScatterPlot to render the current projected data set.
+ */
+export class ProjectorScatterPlotAdapter {
+ generateVisibleLabelRenderParams(
+ ds: DataSet, selectedPointIndices: number[],
+ neighborsOfFirstPoint: NearestEntry[],
+ hoverPointIndex: number): LabelRenderParams {
+ if (ds == null) {
+ return null;
+ }
+
+ const n = selectedPointIndices.length + neighborsOfFirstPoint.length +
+ ((hoverPointIndex != null) ? 1 : 0);
+
+ const visibleLabels = new Uint32Array(n);
+ const scale = new Float32Array(n);
+ const opacityFlags = new Int8Array(n);
+
+ scale.fill(LABEL_SCALE_DEFAULT);
+ opacityFlags.fill(1);
+
+ let dst = 0;
+
+ if (hoverPointIndex != null) {
+ visibleLabels[dst] = hoverPointIndex;
+ scale[dst] = LABEL_SCALE_LARGE;
+ opacityFlags[dst] = 0;
+ ++dst;
+ }
+
+ // Selected points
+ {
+ const n = selectedPointIndices.length;
+ for (let i = 0; i < n; ++i) {
+ visibleLabels[dst] = selectedPointIndices[i];
+ scale[dst] = LABEL_SCALE_LARGE;
+ opacityFlags[dst] = (n === 1) ? 0 : 1;
+ ++dst;
+ }
+ }
+
+ // Neighbors
+ {
+ const n = neighborsOfFirstPoint.length;
+ for (let i = 0; i < n; ++i) {
+ visibleLabels[dst++] = neighborsOfFirstPoint[i].index;
+ }
+ }
+
+ return new LabelRenderParams(
+ visibleLabels, scale, opacityFlags, LABEL_FONT_SIZE, LABEL_FILL_COLOR,
+ LABEL_STROKE_COLOR);
+ }
+
+ generatePointScaleFactorArray(
+ ds: DataSet, selectedPointIndices: number[],
+ neighborsOfFirstPoint: NearestEntry[],
+ hoverPointIndex: number): Float32Array {
+ if (ds == null) {
+ return new Float32Array(0);
+ }
+
+ const scale = new Float32Array(ds.points.length);
+ scale.fill(POINT_SCALE_DEFAULT);
+
+ // Scale up all selected points.
+ {
+ const n = selectedPointIndices.length;
+ for (let i = 0; i < n; ++i) {
+ const p = selectedPointIndices[i];
+ scale[p] = POINT_SCALE_SELECTED;
+ }
+ }
+
+ // Scale up the neighbor points.
+ {
+ const n = neighborsOfFirstPoint.length;
+ for (let i = 0; i < n; ++i) {
+ const p = neighborsOfFirstPoint[i].index;
+ scale[p] = POINT_SCALE_NEIGHBOR;
+ }
+ }
+
+ // Scale up the hover point.
+ if (hoverPointIndex != null) {
+ scale[hoverPointIndex] = POINT_SCALE_HOVER;
+ }
+
+ return scale;
+ }
+
+ generatePointColorArray(
+ ds: DataSet, legendPointColorer: (index: number) => string,
+ selectedPointIndices: number[], neighborsOfFirstPoint: NearestEntry[],
+ hoverPointIndex: number, label3dMode: boolean): Float32Array {
+ if (ds == null) {
+ return new Float32Array(0);
+ }
+
+ const colors = new Float32Array(ds.points.length * 3);
+
+ let unselectedColor = POINT_COLOR_UNSELECTED;
+ let noSelectionColor = POINT_COLOR_NO_SELECTION;
+
+ if (label3dMode) {
+ unselectedColor = LABELS_3D_COLOR_UNSELECTED;
+ noSelectionColor = LABELS_3D_COLOR_NO_SELECTION;
+ }
+
+ // Give all points the unselected color.
+ {
+ const n = ds.points.length;
+ let dst = 0;
+ if (selectedPointIndices.length > 0) {
+ const c = new THREE.Color(unselectedColor);
+ for (let i = 0; i < n; ++i) {
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+ } else {
+ if (legendPointColorer != null) {
+ for (let i = 0; i < n; ++i) {
+ const c = new THREE.Color(legendPointColorer(i));
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+ } else {
+ const c = new THREE.Color(noSelectionColor);
+ for (let i = 0; i < n; ++i) {
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+ }
+ }
+ }
+
+ // Color the selected points.
+ {
+ const n = selectedPointIndices.length;
+ const c = new THREE.Color(POINT_COLOR_SELECTED);
+ for (let i = 0; i < n; ++i) {
+ let dst = selectedPointIndices[i] * 3;
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+ }
+
+ // Color the neighbors.
+ {
+ const n = neighborsOfFirstPoint.length;
+ const c = new THREE.Color(POINT_COLOR_SELECTED);
+ for (let i = 0; i < n; ++i) {
+ let dst = neighborsOfFirstPoint[i].index * 3;
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+ }
+
+ // Color the hover point.
+ if (hoverPointIndex != null) {
+ const c = new THREE.Color(POINT_COLOR_HOVER);
+ let dst = hoverPointIndex * 3;
+ colors[dst++] = c.r;
+ colors[dst++] = c.g;
+ colors[dst++] = c.b;
+ }
+
+ return colors;
+ }
+}
diff --git a/tensorflow/tensorboard/components/vz-projector/renderContext.ts b/tensorflow/tensorboard/components/vz-projector/renderContext.ts
index 16ccf8f937..3da699bd82 100644
--- a/tensorflow/tensorboard/components/vz-projector/renderContext.ts
+++ b/tensorflow/tensorboard/components/vz-projector/renderContext.ts
@@ -42,6 +42,9 @@ export class LabelRenderParams {
* RenderContext contains all of the state required to color and render the data
* set. ScatterPlot passes this to every attached visualizer as part of the
* render callback.
+ * TODO(nicholsonc): This should only contain the data that's changed between
+ * each frame. Data like colors / scale factors / labels should be recomputed
+ * only when they change.
*/
export class RenderContext {
camera: THREE.Camera;
@@ -58,9 +61,9 @@ export class RenderContext {
constructor(
camera: THREE.Camera, cameraTarget: THREE.Vector3, screenWidth: number,
screenHeight: number, nearestCameraSpacePointZ: number,
- farthestCameraSpacePointZ: number,
- labelAccessor: (index: number) => string, pointColors: Float32Array,
- pointScaleFactors: Float32Array, labels: LabelRenderParams) {
+ farthestCameraSpacePointZ: number, pointColors: Float32Array,
+ pointScaleFactors: Float32Array, labelAccessor: (index: number) => string,
+ labels: LabelRenderParams) {
this.camera = camera;
this.cameraTarget = cameraTarget;
this.screenWidth = screenWidth;
diff --git a/tensorflow/tensorboard/components/vz-projector/scatterPlot.ts b/tensorflow/tensorboard/components/vz-projector/scatterPlot.ts
index fbc68e1526..397b8eebed 100644
--- a/tensorflow/tensorboard/components/vz-projector/scatterPlot.ts
+++ b/tensorflow/tensorboard/components/vz-projector/scatterPlot.ts
@@ -609,7 +609,7 @@ export class ScatterPlot {
update() {
this.getPointsCoordinates();
this.visualizers.forEach(v => {
- v.onUpdate();
+ v.onUpdate(this.dataSet);
});
this.render();
}
@@ -633,7 +633,7 @@ export class ScatterPlot {
const rc = new RenderContext(
this.camera, this.orbitCameraControls.target, this.width, this.height,
cameraSpacePointExtents[0], cameraSpacePointExtents[1],
- this.labelAccessor, this.pointColors, this.pointScaleFactors,
+ this.pointColors, this.pointScaleFactors, this.labelAccessor,
this.labels);
// Render first pass to picking target. This render fills pickingTexture
diff --git a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer.ts b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer.ts
index eaa1faede3..bac536e20c 100644
--- a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer.ts
+++ b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer.ts
@@ -61,7 +61,7 @@ export interface ScatterPlotVisualizer {
* Called when the projector updates application state (projection style,
* etc). Generally followed by a render.
*/
- onUpdate();
+ onUpdate(dataSet: DataSet);
/**
* Called when the canvas size changes.
*/
diff --git a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer3DLabels.ts b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer3DLabels.ts
index ae59a5b1f3..92bbd320d0 100644
--- a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer3DLabels.ts
+++ b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizer3DLabels.ts
@@ -194,7 +194,7 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
}
}
- private createLabelGeometry() {
+ private createLabelGeometry(dataSet: DataSet) {
this.processLabelVerts();
this.createColorBuffers();
@@ -220,7 +220,7 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
this.geometry.addAttribute('color', colors);
let lettersSoFar = 0;
- for (let i = 0; i < this.dataSet.points.length; i++) {
+ for (let i = 0; i < dataSet.points.length; i++) {
let label: string = this.labelAccessor(i).toString();
let leftOffset = 0;
// Determine length of word in pixels.
@@ -267,8 +267,8 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
}
}
- for (let i = 0; i < this.dataSet.points.length; i++) {
- let pp = this.dataSet.points[i].projectedPoint;
+ for (let i = 0; i < dataSet.points.length; i++) {
+ let pp = dataSet.points[i].projectedPoint;
this.labelVertexMap[i].forEach((j) => {
this.positions.setXYZ(j, pp[0], pp[1], pp[2]);
});
@@ -287,10 +287,10 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
}
}
- private createLabels() {
+ private createLabels(dataSet: DataSet) {
this.destroyLabels();
if (this.labelAccessor) {
- this.createLabelGeometry();
+ this.createLabelGeometry(dataSet);
}
}
@@ -320,7 +320,7 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
scene: THREE.Scene, sceneIs3D: boolean, backgroundColor: number) {
this.scene = scene;
if (this.labelsMesh == null) {
- this.createLabels();
+ this.createLabels(this.dataSet);
}
if (this.labelsMesh) {
scene.add(this.labelsMesh);
@@ -333,7 +333,7 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
onSetLabelAccessor(labelAccessor: (index: number) => string) {
this.labelAccessor = labelAccessor;
- this.onUpdate();
+ this.onUpdate(this.dataSet);
}
onDataSet(dataSet: DataSet, spriteImage: HTMLImageElement) {
@@ -361,8 +361,8 @@ export class ScatterPlotVisualizer3DLabels implements ScatterPlotVisualizer {
colors.needsUpdate = true;
}
- onUpdate() {
- this.createLabels();
+ onUpdate(dataSet: DataSet) {
+ this.createLabels(dataSet);
if (this.labelsMesh && this.scene) {
this.scene.add(this.labelsMesh);
}
diff --git a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerAxes.ts b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerAxes.ts
index 34197f182f..b3c7825e98 100644
--- a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerAxes.ts
+++ b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerAxes.ts
@@ -83,7 +83,7 @@ export class ScatterPlotVisualizerAxes implements ScatterPlotVisualizer {
onPickingRender(renderContext: RenderContext) {}
onRender(renderContext: RenderContext) {}
- onUpdate() {}
+ onUpdate(dataSet: DataSet) {}
onResize(newWidth: number, newHeight: number) {}
onSetLabelAccessor(labelAccessor: (index: number) => string) {}
}
diff --git a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerSprites.ts b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerSprites.ts
index a350b32bc4..d79718b50e 100644
--- a/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerSprites.ts
+++ b/tensorflow/tensorboard/components/vz-projector/scatterPlotVisualizerSprites.ts
@@ -272,16 +272,16 @@ export class ScatterPlotVisualizerSprites implements ScatterPlotVisualizer {
this.geometry.addAttribute('scaleFactor', scaleFactors);
}
- private updatePositionsArray() {
+ private updatePositionsArray(dataSet: DataSet) {
if (this.geometry == null) {
return;
}
- const n = this.dataSet.points.length;
+ const n = dataSet.points.length;
const positions =
this.geometry.getAttribute('position') as THREE.BufferAttribute;
positions.array = new Float32Array(n * XYZ_NUM_ELEMENTS);
for (let i = 0; i < n; i++) {
- let pp = this.dataSet.points[i].projectedPoint;
+ let pp = dataSet.points[i].projectedPoint;
positions.setXYZ(i, pp[0], pp[1], pp[2]);
}
positions.needsUpdate = true;
@@ -309,12 +309,12 @@ export class ScatterPlotVisualizerSprites implements ScatterPlotVisualizer {
scene.fog = this.fog;
if (this.dataSet) {
this.addSprites(scene);
- this.updatePositionsArray();
+ this.updatePositionsArray(this.dataSet);
}
}
- onUpdate() {
- this.updatePositionsArray();
+ onUpdate(dataSet: DataSet) {
+ this.updatePositionsArray(dataSet);
}
onResize(newWidth: number, newHeight: number) {}
diff --git a/tensorflow/tensorboard/components/vz-projector/vz-projector.ts b/tensorflow/tensorboard/components/vz-projector/vz-projector.ts
index 2556108a2e..0d36fca5f1 100644
--- a/tensorflow/tensorboard/components/vz-projector/vz-projector.ts
+++ b/tensorflow/tensorboard/components/vz-projector/vz-projector.ts
@@ -14,11 +14,11 @@ limitations under the License.
==============================================================================*/
import {ColorOption, DataProto, DataSet, MetadataInfo, Projection, State} from './data';
-import * as logging from './logging';
import {DataProvider, getDataProvider, ServingMode, TensorInfo} from './data-loader';
import {HoverContext, HoverListener} from './hoverContext';
import * as knn from './knn';
-import {LabelRenderParams} from './renderContext';
+import * as logging from './logging';
+import {ProjectorScatterPlotAdapter} from './projectorScatterPlotAdapter';
import {Mode, ScatterPlot} from './scatterPlot';
import {ScatterPlotVisualizer3DLabels} from './scatterPlotVisualizer3DLabels';
import {ScatterPlotVisualizerCanvasLabels} from './scatterPlotVisualizerCanvasLabels';
@@ -33,31 +33,12 @@ import {ProjectionsPanel} from './vz-projector-projections-panel';
// tslint:disable-next-line:no-unused-variable
import {PolymerElement, PolymerHTMLElement} from './vz-projector-util';
-const LABEL_FONT_SIZE = 10;
-const LABEL_SCALE_DEFAULT = 1.0;
-const LABEL_SCALE_LARGE = 1.7;
-const LABEL_FILL_COLOR = 0x000000;
-const LABEL_STROKE_COLOR = 0xFFFFFF;
-
-const POINT_COLOR_UNSELECTED = 0x888888;
-const POINT_COLOR_NO_SELECTION = 0x7575D9;
-const POINT_COLOR_SELECTED = 0xFA6666;
-const POINT_COLOR_HOVER = 0x760B4F;
-const POINT_COLOR_MISSING = 'black';
-
-const LABELS_3D_COLOR_UNSELECTED = 0xFFFFFF;
-const LABELS_3D_COLOR_NO_SELECTION = 0xFFFFFF;
-
-const POINT_SCALE_DEFAULT = 1.0;
-const POINT_SCALE_SELECTED = 1.2;
-const POINT_SCALE_NEIGHBOR = 1.2;
-const POINT_SCALE_HOVER = 1.2;
-
/**
* The minimum number of dimensions the data should have to automatically
* decide to normalize the data.
*/
const THRESHOLD_DIM_NORMALIZE = 50;
+const POINT_COLOR_MISSING = 'black';
export let ProjectorPolymer = PolymerElement({
is: 'vz-projector',
@@ -79,6 +60,7 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
private dataSet: DataSet;
private dom: d3.Selection<any>;
+ private projectorScatterPlotAdapter: ProjectorScatterPlotAdapter;
private scatterPlot: ScatterPlot;
private dim: number;
@@ -256,92 +238,6 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
return colorer;
}
- private generateVisibleLabelRenderParams(
- selectedPointIndices: number[], neighborsOfFirstPoint: knn.NearestEntry[],
- hoverPointIndex: number): LabelRenderParams {
- if (this.currentDataSet == null) {
- return null;
- }
-
- const n = selectedPointIndices.length + neighborsOfFirstPoint.length +
- ((hoverPointIndex != null) ? 1 : 0);
-
- const visibleLabels = new Uint32Array(n);
- const scale = new Float32Array(n);
- const opacityFlags = new Int8Array(n);
-
- scale.fill(LABEL_SCALE_DEFAULT);
- opacityFlags.fill(1);
-
- let dst = 0;
-
- if (hoverPointIndex != null) {
- visibleLabels[dst] = hoverPointIndex;
- scale[dst] = LABEL_SCALE_LARGE;
- opacityFlags[dst] = 0;
- ++dst;
- }
-
- // Selected points
- {
- const n = selectedPointIndices.length;
- for (let i = 0; i < n; ++i) {
- visibleLabels[dst] = selectedPointIndices[i];
- scale[dst] = LABEL_SCALE_LARGE;
- opacityFlags[dst] = (n === 1) ? 0 : 1;
- ++dst;
- }
- }
-
- // Neighbors
- {
- const n = neighborsOfFirstPoint.length;
- for (let i = 0; i < n; ++i) {
- visibleLabels[dst++] = neighborsOfFirstPoint[i].index;
- }
- }
-
- return new LabelRenderParams(
- visibleLabels, scale, opacityFlags, LABEL_FONT_SIZE, LABEL_FILL_COLOR,
- LABEL_STROKE_COLOR);
- }
-
- private generateScatterPlotScaleFactorArray(
- selectedPointIndices: number[], neighborsOfFirstPoint: knn.NearestEntry[],
- hoverPointIndex: number): Float32Array {
- if (this.currentDataSet == null) {
- return new Float32Array(0);
- }
-
- const scale = new Float32Array(this.currentDataSet.points.length);
- scale.fill(POINT_SCALE_DEFAULT);
-
- // Scale up all selected points.
- {
- const n = selectedPointIndices.length;
- for (let i = 0; i < n; ++i) {
- const p = selectedPointIndices[i];
- scale[p] = POINT_SCALE_SELECTED;
- }
- }
-
- // Scale up the neighbor points.
- {
- const n = neighborsOfFirstPoint.length;
- for (let i = 0; i < n; ++i) {
- const p = neighborsOfFirstPoint[i].index;
- scale[p] = POINT_SCALE_NEIGHBOR;
- }
- }
-
- // Scale up the hover point.
- if (hoverPointIndex != null) {
- scale[hoverPointIndex] = POINT_SCALE_HOVER;
- }
-
- return scale;
- }
-
private get3DLabelModeButton(): any {
return this.querySelector('#labels3DMode');
}
@@ -351,90 +247,6 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
return (label3DModeButton as any).active;
}
- private generateScatterPlotColorArray(
- legendPointColorer: (index: number) => string,
- selectedPointIndices: number[], neighborsOfFirstPoint: knn.NearestEntry[],
- hoverPointIndex: number): Float32Array {
- if (this.currentDataSet == null) {
- return new Float32Array(0);
- }
-
- const colors = new Float32Array(this.currentDataSet.points.length * 3);
-
- let unselectedColor = POINT_COLOR_UNSELECTED;
- let noSelectionColor = POINT_COLOR_NO_SELECTION;
-
- if (this.get3DLabelMode()) {
- unselectedColor = LABELS_3D_COLOR_UNSELECTED;
- noSelectionColor = LABELS_3D_COLOR_NO_SELECTION;
- }
-
- // Give all points the unselected color.
- {
- const n = this.currentDataSet.points.length;
- let dst = 0;
- if (selectedPointIndices.length > 0) {
- const c = new THREE.Color(unselectedColor);
- for (let i = 0; i < n; ++i) {
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
- } else {
- if (legendPointColorer != null) {
- for (let i = 0; i < n; ++i) {
- const c = new THREE.Color(legendPointColorer(i));
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
- } else {
- const c = new THREE.Color(noSelectionColor);
- for (let i = 0; i < n; ++i) {
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
- }
- }
- }
-
- // Color the selected points.
- {
- const n = selectedPointIndices.length;
- const c = new THREE.Color(POINT_COLOR_SELECTED);
- for (let i = 0; i < n; ++i) {
- let dst = selectedPointIndices[i] * 3;
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
- }
-
- // Color the neighbors.
- {
- const n = neighborsOfFirstPoint.length;
- const c = new THREE.Color(POINT_COLOR_SELECTED);
- for (let i = 0; i < n; ++i) {
- let dst = neighborsOfFirstPoint[i].index * 3;
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
- }
-
- // Color the hover point.
- if (hoverPointIndex != null) {
- const c = new THREE.Color(POINT_COLOR_HOVER);
- let dst = hoverPointIndex * 3;
- colors[dst++] = c.r;
- colors[dst++] = c.g;
- colors[dst++] = c.b;
- }
-
- return colors;
- }
-
clearSelectionAndHover() {
this.notifySelectionChanged([]);
this.notifyHoverOverPoint(null);
@@ -497,6 +309,8 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
this.scatterPlot.resize();
});
+ this.projectorScatterPlotAdapter = new ProjectorScatterPlotAdapter();
+
this.scatterPlot = new ScatterPlot(
this.getScatterContainer(), i => '' +
this.currentDataSet.points[i].metadata[this.selectedLabelOption],
@@ -534,16 +348,22 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
}
private updateScatterPlot() {
- const pointColors = this.generateScatterPlotColorArray(
- this.getLegendPointColorer(this.selectedColorOption),
- this.selectedPointIndices, this.neighborsOfFirstPoint,
- this.hoverPointIndex);
- const pointScaleFactors = this.generateScatterPlotScaleFactorArray(
- this.selectedPointIndices, this.neighborsOfFirstPoint,
- this.hoverPointIndex);
- const labels = this.generateVisibleLabelRenderParams(
- this.selectedPointIndices, this.neighborsOfFirstPoint,
- this.hoverPointIndex);
+ const dataSet = this.currentDataSet;
+ const selectedSet = this.selectedPointIndices;
+ const hoverIndex = this.hoverPointIndex;
+ const neighbors = this.neighborsOfFirstPoint;
+ const pointColorer = this.getLegendPointColorer(this.selectedColorOption);
+
+ const pointColors =
+ this.projectorScatterPlotAdapter.generatePointColorArray(
+ dataSet, pointColorer, selectedSet, neighbors, hoverIndex,
+ this.get3DLabelMode());
+ const pointScaleFactors =
+ this.projectorScatterPlotAdapter.generatePointScaleFactorArray(
+ dataSet, selectedSet, neighbors, hoverIndex);
+ const labels =
+ this.projectorScatterPlotAdapter.generateVisibleLabelRenderParams(
+ dataSet, selectedSet, neighbors, hoverIndex);
this.scatterPlot.setPointColors(pointColors);
this.scatterPlot.setPointScaleFactors(pointScaleFactors);
@@ -564,10 +384,8 @@ export class Projector extends ProjectorPolymer implements SelectionContext,
scatterPlot.addVisualizer(new ScatterPlotVisualizer3DLabels());
} else {
scatterPlot.addVisualizer(new ScatterPlotVisualizerSprites());
-
scatterPlot.addVisualizer(
new ScatterPlotVisualizerTraces(selectionContext));
-
scatterPlot.addVisualizer(
new ScatterPlotVisualizerCanvasLabels(this.getScatterContainer()));
}