From fa0f18d8fe8a405dcefdd38bcce2ea88d07d4ea6 Mon Sep 17 00:00:00 2001 From: r59q Date: Wed, 3 Jul 2024 20:46:44 +0200 Subject: [PATCH] Added colors to gestures --- src/components/Gesture.svelte | 4 + src/components/filters/FilterListRow.svelte | 15 - .../knngraph/KNNModelGraphController.ts | 8 +- .../graphs/knngraph/KNNModelGraphDrawer.ts | 11 +- .../graphs/knngraph/KnnModelGraph.svelte | 9 + .../output/OutputGestureStack.svelte | 4 + src/exampleDataset.json | 7633 +++++++++++++++-- src/pages/filter/D3Plot.svelte | 29 +- src/script/domain/stores/gesture/Gesture.ts | 28 +- src/script/domain/stores/gesture/Gestures.ts | 4 + .../LocalStorageGestureRepository.ts | 1 + 11 files changed, 6997 insertions(+), 749 deletions(-) diff --git a/src/components/Gesture.svelte b/src/components/Gesture.svelte index c350fe76c..dcf8aabe4 100644 --- a/src/components/Gesture.svelte +++ b/src/components/Gesture.svelte @@ -187,6 +187,10 @@
+
+
-
{/key} diff --git a/src/components/graphs/knngraph/KNNModelGraphController.ts b/src/components/graphs/knngraph/KNNModelGraphController.ts index 4b0089197..921649556 100644 --- a/src/components/graphs/knngraph/KNNModelGraphController.ts +++ b/src/components/graphs/knngraph/KNNModelGraphController.ts @@ -30,6 +30,7 @@ class KNNModelGraphController { private rotationX: Writable; private rotationY: Writable; private rotationZ: Writable; + private graphColors: string[]; private origin: Writable<{ x: number; y: number }>; private scale: Writable; private graphDrawer: KNNModelGraphDrawer; @@ -46,6 +47,7 @@ class KNNModelGraphController { private trainingDataGetter: () => TrainingData, origin: { x: number; y: number }, classId: string, + colors: string[], axis?: Axes, ) { this.filters = stores.getClassifier().getFilters(); @@ -56,6 +58,7 @@ class KNNModelGraphController { this.rotationZ = writable(0); this.scale = writable(100); this.origin = writable(origin); + this.graphColors = colors; const noOfPoints = this.trainingData .map(el => el.length) @@ -112,7 +115,7 @@ class KNNModelGraphController { return [this.arrayToPoint(sample.value)]; } - private getControllerData() { + private getControllerData(): { config: GraphDrawConfig, data: TimestampedData[] } { const classifier = stores.getClassifier(); const xRot = get(this.rotationX); const yRot = get(this.rotationY); @@ -156,7 +159,8 @@ class KNNModelGraphController { zRot, origin, scale, - } as GraphDrawConfig, + colors: this.graphColors + }, data: liveData, }; } diff --git a/src/components/graphs/knngraph/KNNModelGraphDrawer.ts b/src/components/graphs/knngraph/KNNModelGraphDrawer.ts index 0b7ee01fd..941fe1168 100644 --- a/src/components/graphs/knngraph/KNNModelGraphDrawer.ts +++ b/src/components/graphs/knngraph/KNNModelGraphDrawer.ts @@ -21,6 +21,7 @@ export type GraphDrawConfig = { zRot: number; origin: { x: number; y: number }; scale: number; + colors: string[]; // The number of colors should be equal to the number of classes plus one for live data }; export type GrahpDrawData = { @@ -39,15 +40,17 @@ class KNNModelGraphDrawer { constructor( private svg: d3.Selection, private classId: string, - ) {} + ) { } public drawLiveData = (drawConfig: GraphDrawConfig, drawData: Point3D) => { if (isNaN(drawData.y)) { return; } const pointTransformer = this.getPointTransformer(drawConfig); - const color = - StaticConfiguration.gestureColors[stores.getGestures().getNumberOfGestures()]; + const color = drawConfig.colors.slice(-1)[0] // Fetch the last element of the colors array + if (!color) { + throw new Error('No color available for live data'); + } const drawableLivePoint: DrawablePoint = { pointTransformed: pointTransformer(drawData), color, @@ -118,7 +121,7 @@ class KNNModelGraphDrawer { drawData.forEach((clazz, classIndex) => { clazz.forEach((sample, exampleIndex) => { sample.forEach((axisValue, axisIndex) => { - const color = StaticConfiguration.gestureColors[classIndex]; + const color = drawConfig.colors[classIndex]; const transformedPoint: Point3DTransformed = pointTransformer(axisValue); this.drawnTrainingPoints.push(transformedPoint); drawablePoints.push({ diff --git a/src/components/graphs/knngraph/KnnModelGraph.svelte b/src/components/graphs/knngraph/KnnModelGraph.svelte index cf3adeca5..9f4e6e419 100644 --- a/src/components/graphs/knngraph/KnnModelGraph.svelte +++ b/src/components/graphs/knngraph/KnnModelGraph.svelte @@ -16,6 +16,7 @@ import KnnPointToolTipView from './KnnPointToolTipView.svelte'; import { stores } from '../../../script/stores/Stores'; import { get } from 'svelte/store'; + import StaticConfiguration from '../../../StaticConfiguration'; const classifierFactory = new ClassifierFactory(); @@ -51,11 +52,19 @@ const initSingle = (axis: Axes) => { const svgSingle = d3.select('.d3-3d-single'); + const graphColors = [ + ...$gestures.map(data => data.color), + StaticConfiguration.gestureColors[$gestures.length], + ]; + if (graphColors.length <= $gestures.length) { + throw new Error('Not enough colors'); + } const controller = new KNNModelGraphController( svgSingle, () => dataGetter(), { x: canvasWidth / 2, y: canvasHeight / 2 }, 'd3-3d-single-', + graphColors, axis, ); return controller; diff --git a/src/components/output/OutputGestureStack.svelte b/src/components/output/OutputGestureStack.svelte index b02fd811f..44df6b3a1 100644 --- a/src/components/output/OutputGestureStack.svelte +++ b/src/components/output/OutputGestureStack.svelte @@ -194,6 +194,10 @@
+
+
filter.filter(data); - let color: d3.ScaleOrdinal | undefined = undefined; let classList: { name: string; id: number }[] = []; const recordings = createDataRepresentation(); // side effect: updates classList and color @@ -126,11 +127,12 @@ }); } - function getColorForClass(gestureID: string) { - if (color === undefined) { - throw new Error('Cannot get color for gesture, color function not defined'); + function getColorForClass(gestureID: number): string { + if (gestureID === uniqueLiveDataID) { + return StaticConfiguration.liveGraphColors[gestures.getNumberOfGestures()]; } - return color(gestureID); + + return gestures.getGesture(gestureID).getColor(); } function getStrokeColor(gesture: unknown) { @@ -138,7 +140,7 @@ if (!gestureID) { throw new Error('The given gesture did not contain a gestureClass'); } - return getColorForClass(gestureID.toString()); + return getColorForClass(gestureID); } function createLiveData() { @@ -186,11 +188,6 @@ recordings.push({ ID, gestureClassName, gestureClassID, x, y, z }); }); }); - const classesIDs = [ - ...classes.map(c => c.id.toString()), - uniqueLiveDataID.toString(), - ]; - color = d3.scaleOrdinal().domain(classesIDs).range(d3.schemeSet3); classList = classes; return recordings; } @@ -216,7 +213,7 @@ if (!id) { throw new Error('The given gesture did not contain a gestureClass'); } - return getColorForClass(id.toString()); + return getColorForClass(id); }) .style('opacity', '1'); } @@ -242,10 +239,10 @@ .attr('d', path) .style('fill', 'none') .style('stroke', function (gesture: RecordingRepresentation) { - return getColorForClass(gesture.gestureClassID.toString()); + return getColorForClass(gesture.gestureClassID); }) .style('opacity', function (gesture: RecordingRepresentation) { - return 0.8; + return 0.4; }) .style('stroke-width', function (gesture: RecordingRepresentation) { return 4; @@ -309,8 +306,8 @@
{#each classList as c}
highlight(null, { gestureClassID: c.id })} on:mouseleave={doNotHighlight}> {c.name} diff --git a/src/script/domain/stores/gesture/Gesture.ts b/src/script/domain/stores/gesture/Gesture.ts index 9ea6b1d43..feacd5a1d 100644 --- a/src/script/domain/stores/gesture/Gesture.ts +++ b/src/script/domain/stores/gesture/Gesture.ts @@ -73,6 +73,23 @@ class Gesture implements Readable { return get(this.store).name; } + /** + * Get the HEX color assigned to this gesture. + */ + public getColor(): string { + return get(this.store).color; + } + + /** + * Set the HEX color assigned to this gesture. + */ + public setColor(color: string): void { + this.persistedData.update(val => { + val.color = color; + return val; + }); + } + public addRecording(recording: RecordingData) { this.onRecordingsChanged(); this.persistedData.update(newVal => { @@ -131,13 +148,14 @@ class Gesture implements Readable { private deriveStore(): Readable { return derived([this.persistedData, this.gestureConfidence], stores => { - const peristantData = stores[0]; + const persistantData = stores[0]; const confidenceData = stores[1]; const derivedData: GestureData = { - ID: peristantData.ID, - name: peristantData.name, - recordings: peristantData.recordings, - output: peristantData.output, + ID: persistantData.ID, + name: persistantData.name, + recordings: persistantData.recordings, + output: persistantData.output, + color: persistantData.color, confidence: { currentConfidence: confidenceData.confidence, requiredConfidence: confidenceData.requiredConfidence, diff --git a/src/script/domain/stores/gesture/Gestures.ts b/src/script/domain/stores/gesture/Gestures.ts index c3a96bc27..3cf4ce090 100644 --- a/src/script/domain/stores/gesture/Gestures.ts +++ b/src/script/domain/stores/gesture/Gestures.ts @@ -21,6 +21,7 @@ export type PersistantGestureData = { ID: GestureID; recordings: RecordingData[]; output: GestureOutput; + color: string; }; export type RecordingData = { @@ -90,11 +91,13 @@ class Gestures implements Readable { public createGesture(name = ''): Gesture { const newId = Date.now(); + const color = StaticConfiguration.gestureColors[this.getNumberOfGestures() % StaticConfiguration.gestureColors.length]; return this.addGestureFromPersistedData({ ID: newId, recordings: [], output: {}, //TODO: ADD DEFAULT VALUES HERE name: name, + color }); } @@ -148,6 +151,7 @@ class Gestures implements Readable { name: gesture.getName(), recordings: gesture.getRecordings(), output: gesture.getOutput(), + color: gesture.getColor(), confidence: { currentConfidence: gesture.getConfidence().getCurrentConfidence(), requiredConfidence: gesture.getConfidence().getRequiredConfidence(), diff --git a/src/script/repository/LocalStorageGestureRepository.ts b/src/script/repository/LocalStorageGestureRepository.ts index ebbe83f1b..48608bae2 100644 --- a/src/script/repository/LocalStorageGestureRepository.ts +++ b/src/script/repository/LocalStorageGestureRepository.ts @@ -88,6 +88,7 @@ class LocalStorageGestureRepository implements GestureRepository { ID: gesture.getId(), name: gesture.getName(), recordings: gesture.getRecordings(), + color: gesture.getColor(), output: gesture.getOutput(), }; }