Commit 3b622bce authored by Kruyff,D.L.W. (Dylan)'s avatar Kruyff,D.L.W. (Dylan)
Browse files

Better visualisations + multivariate data


Former-commit-id: 4f8966d6
parent af9ce874
...@@ -6,17 +6,19 @@ export interface RawData { ...@@ -6,17 +6,19 @@ export interface RawData {
} }
export interface LshData { export interface LshData {
candidates: number[]; candidates: number[][][];
distances: number[]; average_candidates: number[];
hash_functions: number[];// number[][][][]; average_distances: number[];
distances: number[][][];
hash_functions: number[][][][];
parameters?: number[]; parameters?: number[];
} }
export interface TableInfoData { export interface TableInfoData {
prototypes: { prototypes: {
average: number[]; average: number[][];
min: number[]; min: number[][];
max: number[]; max: number[][];
}[]; }[];
distances: number[][]; distances: number[][];
} }
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
margin-right: 20px; margin-right: 20px;
display: flex; display: flex;
justify-content: center; justify-content: center;
border-right: 1px solid;
border-bottom: 1px solid;
} }
.subplot-container { .subplot-container {
display: flex; display: flex;
flex-wrap: wrap;
overflow-x: scroll; overflow-x: scroll;
width: 95%; width: 95%;
} }
......
...@@ -44,13 +44,13 @@ export class LabelingWindowComponent implements OnInit { ...@@ -44,13 +44,13 @@ export class LabelingWindowComponent implements OnInit {
} }
async showSamples() { async showSamples() {
this.topk = this.state.lshData.candidates this.topk = this.state.lshData.average_candidates
.filter((candidate) => this.state.labels[candidate] !== true) .filter((candidate) => this.state.labels[candidate] !== true)
.slice(0, this.k); .slice(0, this.k);
this.subplots = []; this.subplots = [];
const values: number[][][] = await this.state.getWindow(this.topk); const values: number[][][] = await this.state.getWindow(this.topk);
for (const idx in this.topk) { for (const idx in this.topk) {
const window = values[idx].slice(0, 1); const window = values[idx];
const data = []; const data = [];
window.forEach((channel: number[], index: number) => { window.forEach((channel: number[], index: number) => {
data.push({ data.push({
...@@ -70,7 +70,7 @@ export class LabelingWindowComponent implements OnInit { ...@@ -70,7 +70,7 @@ export class LabelingWindowComponent implements OnInit {
data: data, data: data,
layout: { layout: {
grid: { grid: {
rows: 1, //this.state.queryWindow.length, rows: this.state.queryWindow.length,
columns: 1, columns: 1,
subplots: subplots, subplots: subplots,
}, },
...@@ -85,7 +85,7 @@ export class LabelingWindowComponent implements OnInit { ...@@ -85,7 +85,7 @@ export class LabelingWindowComponent implements OnInit {
b: 0, b: 0,
pad: 4 pad: 4
}, },
height: 100, height: 100 * values[0].length,
width: 300, width: 300,
titlefont: { titlefont: {
size: 9 size: 9
......
...@@ -20,7 +20,7 @@ export class LabelsComponent implements OnInit { ...@@ -20,7 +20,7 @@ export class LabelsComponent implements OnInit {
async createSubplots() { async createSubplots() {
this.goodLabels = []; this.goodLabels = [];
this.badLabels = []; this.badLabels = [];
const labelWindows: number[][] = await this.state.getWindow(Object.keys(this.state.labels).map(Number)); const labelWindows: number[][][] = await this.state.getWindow(Object.keys(this.state.labels).map(Number));
Object.keys(this.state.labels).forEach((key, i) => { Object.keys(this.state.labels).forEach((key, i) => {
const index = Number(key); const index = Number(key);
const plot = const plot =
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<app-overview-window style="z-index: 10"></app-overview-window> <app-overview-window style="z-index: 10"></app-overview-window>
<mat-tab-group animationDuration="0ms" (selectedTabChange)="changeTab($event)"> <mat-tab-group animationDuration="0ms" (selectedTabChange)="changeTab($event)">
<mat-tab label="Training"> <mat-tab label="Training">
<app-labeling-window></app-labeling-window>
<app-table-overview></app-table-overview> <app-table-overview></app-table-overview>
<app-labeling-window></app-labeling-window>
</mat-tab> </mat-tab>
<mat-tab label="Labeled data"> <mat-tab label="Labeled data">
<app-labels></app-labels> <app-labels></app-labels>
......
<zingchart-angular #chart [id]="id" [config]="config" (mousewheel)="zoom($event)" (click)="clicked($event)" [height]="150"></zingchart-angular> <zingchart-angular #chart [id]="id" [config]="config" (mousewheel)="zoom($event)" (click)="clicked($event)" [height]="300"></zingchart-angular>
...@@ -16,6 +16,7 @@ export class OverviewWindowComponent implements OnInit { ...@@ -16,6 +16,7 @@ export class OverviewWindowComponent implements OnInit {
public series = []; public series = [];
public goodLabels = []; public goodLabels = [];
public badLabels = []; public badLabels = [];
public candidateLabels = [];
public data; public data;
public layout; public layout;
...@@ -93,9 +94,6 @@ export class OverviewWindowComponent implements OnInit { ...@@ -93,9 +94,6 @@ export class OverviewWindowComponent implements OnInit {
}); });
// Initialize channels // Initialize channels
this.state.rawData.forEach((channel, index) => { this.state.rawData.forEach((channel, index) => {
if (index !== 0) {
return;
}
const data = []; const data = [];
for (let i = 0; i < channel.values.length; i++) { for (let i = 0; i < channel.values.length; i++) {
data.push([i, channel.values[i]]); data.push([i, channel.values[i]]);
...@@ -150,37 +148,59 @@ export class OverviewWindowComponent implements OnInit { ...@@ -150,37 +148,59 @@ export class OverviewWindowComponent implements OnInit {
}; };
console.log(this.config); console.log(this.config);
console.log("showing plot"); console.log("showing plot");
await this.debugClicked();
} }
async updatePlot() { async updatePlot() {
console.log('updating plot');
if (!this.state.queryWindow) {
return;
}
this.goodLabels = []; this.goodLabels = [];
this.badLabels = []; this.badLabels = [];
this.markers = []; this.markers = [];
for (const index in this.state.labels) { for (const index in this.state.labels) {
if (this.state.labels[index]) { if (this.state.labels[index]) {
this.goodLabels.push([Number(index) * (12000 / 6), 0]); this.goodLabels.push([Number(index), 0]);
this.markers.push({ this.markers.push({
type: 'area', type: 'area',
// BUG: For some reason the range values are multiplied by 10 // BUG: For some reason the range values are multiplied by 10
range: [Number(index) * (12000 / 6) / 10, (Number(index) * (12000 / 6) + this.state.windowSize) / 10], range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10],
backgroundColor: '#4caf50', backgroundColor: "#4caf50",
}); });
} else { } else {
this.badLabels.push([Number(index) * (12000 / 6), 0]); this.badLabels.push([Number(index), -1]);
this.markers.push({ this.markers.push({
type: 'area', type: 'area',
// BUG: For some reason the range values are multiplied by 10 // BUG: For some reason the range values are multiplied by 10
range: [Number(index) * (12000 / 6) / 10, (Number(index) * (12000 / 6) + this.state.windowSize) / 10], range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10],
backgroundColor: '#f44336', backgroundColor: "#f44336",
}); });
} }
} }
this.series[1].values = this.goodLabels; // for (const index of this.state.lshData.average_candidates) {
this.series[2].values = this.badLabels; // this.candidateLabels.push([Number(index), 1]);
this.config.scaleX.markers = this.markers; // this.markers.push({
zingchart.exec('zingchart-ng-1', 'setdata', { // type: 'area',
// // BUG: For some reason the range values are multiplied by 10
// range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10],
// backgroundColor: '#b1a343',
// });
// }
console.log(this.markers);
for (const channel of this.config.graphset) {
if (channel.type === 'line') {
channel.scaleX.markers = this.markers;
} else {
channel.series[0].values = this.goodLabels;
channel.series[1].values = this.badLabels;
channel.series[2].values = this.candidateLabels;
}
}
this.chart.setdata({
data: this.config data: this.config
}); });
} }
async updateCandidates(sliderIndex) { async updateCandidates(sliderIndex) {
......
...@@ -27,5 +27,11 @@ ...@@ -27,5 +27,11 @@
justify-content: center; justify-content: center;
} }
mat-slider {
display: flex;
justify-content: center;
width: 400px;
}
line { stroke: #5e4646; } line { stroke: #5e4646; }
circle { stroke: #fff; stroke-width: 1.5px; } circle { stroke: #fff; stroke-width: 1.5px; }
<svg id="visual" width='500' height='300'></svg> <!--<svg id="visual" width='500' height='300'></svg>-->
<div *ngIf="data" class="histogram">
<div class="container">
<plotly-plot (hover)="onHover($event)" [data]="hist.data" [layout]="hist.layout"></plotly-plot>
</div>
<div class="slider">
<mat-slider [min]="0" [max]="maxLength" step="1" [value]="sliderValue" (input)="setSliderValue($event)" thumbLabel tickInterval="5"></mat-slider>
</div>
</div>
<div *ngIf="data" class="container"> <div *ngIf="data" class="container">
<div class="window"> <div class="window">
<div class="plots"> <div class="plots">
<plotly-plot *ngFor="let data of this.data; index as i;" [class.hide]="i != sliderValue" [data]="data" [layout]="layout"></plotly-plot> <plotly-plot *ngFor="let data of this.data; index as i;" [class.hide]="i != sliderValue" [data]="data" [layout]="layout"></plotly-plot>
</div> </div>
</div> </div>
<mat-slider vertical min="0" [max]="maxLength" step="1" [(value)]="sliderValue" thumbLabel tickInterval="5"></mat-slider>
</div> </div>
<script src='https://d3js.org/d3.v4.min.js'></script> <script src='https://d3js.org/d3.v4.min.js'></script>
import { Component, OnInit } from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {StateService} from '../state.service'; import {StateService} from '../state.service';
import * as d3 from 'd3'; import * as d3 from 'd3';
...@@ -8,9 +8,11 @@ import * as d3 from 'd3'; ...@@ -8,9 +8,11 @@ import * as d3 from 'd3';
styleUrls: ['./progress-view.component.css'] styleUrls: ['./progress-view.component.css']
}) })
export class ProgressViewComponent implements OnInit { export class ProgressViewComponent implements OnInit {
@ViewChild('chart') chart;
public plot; public plot;
public data; public data;
public layout; public layout;
public hist;
public amountOfCandidates; public amountOfCandidates;
public hover = 0; public hover = 0;
...@@ -20,23 +22,60 @@ export class ProgressViewComponent implements OnInit { ...@@ -20,23 +22,60 @@ export class ProgressViewComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.state.onNewTableInfo.subscribe(() => { this.showgraph(); }); this.state.onNewTableInfo.subscribe(() => { this.showgraph(); });
this.state.onNewTableInfo.subscribe(() => { this.showHistogram(); });
}
showHistogram() {
const table = this.state._averageTable;
this.hist = {
data: [{
x: Object.keys(table),
y: Object.values(table).map((values: number[]) => values.length), // / (this.service.rawValues.length - this.service.windowSize)),
type: 'bar',
opacity: 0.5,
marker: {
color: Object.keys(table).map((key) => {
return this.getColor(Number(key) / Number(Object.keys(table)[Object.keys(table).length - 1]));
})
}
}],
layout: {
hovermode: 'closest',
autosize: true,
margin: {
l: 10,
r: 10,
t: 10,
b: 10,
pad: 4
},
xaxis: {
showticklabels: false
},
yaxis: {
showticklabels: false
},
height: 200,
width: 400,
}
};
}
onHover(data) {
console.log(data);
this.setSliderValue({value: data.points[0].x});
} }
hoverPlot(averages) { hoverPlot(averages) {
const subplots = [];
this.data = averages.map((prototype) => { this.data = averages.map((prototype) => {
return [ const channelData = [];
{ prototype.max.forEach((channel, index) => {
x: [...Array(prototype.average.length).keys()], channelData.push({
y: prototype.average, x: [...Array(channel.length).keys()],
type: 'line', y: channel,
line: { xaxis: 'x',
color: 'red', yaxis: `y${index + 2}`,
width: 3
}
},
{
x: [...Array(prototype.average.length).keys()],
y: prototype.max,
type: 'scatter', type: 'scatter',
fill: null, fill: null,
mode: 'lines', mode: 'lines',
...@@ -44,10 +83,14 @@ export class ProgressViewComponent implements OnInit { ...@@ -44,10 +83,14 @@ export class ProgressViewComponent implements OnInit {
color: 'rgb(55, 128, 191)', color: 'rgb(55, 128, 191)',
width: 3 width: 3
} }
}, });
{ });
x: [...Array(prototype.average.length).keys()], prototype.min.forEach((channel, index) => {
y: prototype.min, channelData.push({
x: [...Array(channel.length).keys()],
y: channel,
xaxis: 'x',
yaxis: `y${index + 2}`,
type: 'scatter', type: 'scatter',
fill: 'tonexty', fill: 'tonexty',
mode: 'lines', mode: 'lines',
...@@ -55,10 +98,32 @@ export class ProgressViewComponent implements OnInit { ...@@ -55,10 +98,32 @@ export class ProgressViewComponent implements OnInit {
color: 'rgb(55, 128, 191)', color: 'rgb(55, 128, 191)',
width: 3 width: 3
} }
}, });
]; });
prototype.average.forEach((channel, index) => {
channelData.push({
x: [...Array(channel.length).keys()],
y: channel,
xaxis: 'x',
yaxis: `y${index + 2}`,
type: 'line',
line: {
color: 'red',
width: 3
}
});
});
return channelData;
}); });
for (let index = 0; index < this.state.queryWindow.length; index++) {
subplots.push([`xy${index + 2}`]);
}
this.layout = { this.layout = {
grid: {
rows: this.state.queryWindow.length,
columns: 1,
subplots: subplots,
},
showlegend: false, showlegend: false,
hovermode: 'closest', hovermode: 'closest',
autosize: true, autosize: true,
...@@ -77,15 +142,21 @@ export class ProgressViewComponent implements OnInit { ...@@ -77,15 +142,21 @@ export class ProgressViewComponent implements OnInit {
zeroline: false, zeroline: false,
showticklabels: false, showticklabels: false,
}, },
height: 300, height: 400,
width: 300, width: 400,
}; };
this.state.queryWindow.forEach((channel: number[], index: number) => {
this.layout[`yaxis${index + 2}`] = {
zeroline: false,
showticklabels: false,
};
});
} }
public set sliderValue(v: number) { public setSliderValue(v) {
this._sliderValue = v; this._sliderValue = v.value;
d3.selectAll('circle').transition().style('stroke', undefined); d3.selectAll('circle').transition().style('stroke', undefined);
d3.select('#node-' + v).transition().style('stroke', 'black').style('stroke-width', 20); d3.select('#node-' + v.value).transition().style('stroke', 'black').style('stroke-width', 20);
} }
public get sliderValue(): number { public get sliderValue(): number {
...@@ -93,11 +164,11 @@ export class ProgressViewComponent implements OnInit { ...@@ -93,11 +164,11 @@ export class ProgressViewComponent implements OnInit {
} }
public get maxLength(): number { public get maxLength(): number {
return Object.keys(this.table).length; return Object.keys(this.table).length - 1;
} }
public get table() { public get table() {
return this.state.table; return this.state._averageTable;
} }
async showgraph() { async showgraph() {
...@@ -107,91 +178,91 @@ export class ProgressViewComponent implements OnInit { ...@@ -107,91 +178,91 @@ export class ProgressViewComponent implements OnInit {
this.hoverPlot(this.state.tableInfo.prototypes); this.hoverPlot(this.state.tableInfo.prototypes);
const distances = this.state.tableInfo.distances; const distances = this.state.tableInfo.distances;
for (const key in this.table) { // for (const key in this.table) {
const size = this.table[key].length; // const size = this.table[key].length;
nodes.push({id: key, group: Number(key), size: size}); // nodes.push({id: key, group: Number(key), size: size});
} // }
for (const key in this.table) { // for (const key in this.table) {
for (const key2 in this.table) { // for (const key2 in this.table) {
if (key === key2) { // if (key === key2) {
continue; // continue;
} // }
links.push({source: key, target: key2, value: 0.001 * (100 - 5 * distances[keys.indexOf(key)][keys.indexOf(key2)])}); // links.push({source: key, target: key2, value: 0.001 * (100 - 5 * distances[keys.indexOf(key)][keys.indexOf(key2)])});
} // }
} // }
const graph = {nodes, links}; // const graph = {nodes, links};
//
const svg = d3.select('#visual'); // const svg = d3.select('#visual');
const width = +svg.attr('width'); // const width = +svg.attr('width');