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

Merge mts to master


Former-commit-id: 58b61c74
parents ecd7e693 5b836d45
import { Injectable } from '@angular/core';
export interface RawData {
index: string[];
values: number[];
index: string[][];
values: number[][];
}
export interface LshData {
candidates: number[];
distances: number[];
hash_functions: number[];// number[][][][];
candidates: number[][][];
distances: number[][][];
average_candidates: number[];
average_distances: number[];
tables: {[bucket: string]: number[]}[];
average_table: {[bucket: string]: number[]};
samples: number[];
hash_functions: number[][];
parameters?: number[];
}
export interface TableInfoData {
prototypes: {
average: number[];
min: number[];
max: number[];
average: number[][];
min: number[][];
max: number[][];
}[];
distances: number[][];
}
export interface Parameters {
windowsize: number;
hashsize: number;
tablesize: number;
stepsize: number;
}
@Injectable({
providedIn: 'root'
})
/**
* This service acts as the interface between the client and server side.
*/
export class ApiService {
constructor() { }
// Read input data
async readFile(): Promise<RawData> {
/**
* Read input data. The format is a list of channels, where each channel is an object of type RawData
*/
async readFile(): Promise<RawData[]> {
const response = await fetch('http://127.0.0.1:5000/read-data');
return await response.json();
}
// Split data into windows and normalize
async createWindows(parameters): Promise<any> {
/**
* Split the data into windows (server side)
*/
async createWindows(parameters: Parameters): Promise<any> {
const postData = {parameters};
const response = await fetch('http://127.0.0.1:5000/create-windows', {
await fetch('http://127.0.0.1:5000/create-windows', {
method: 'POST',
headers: {
'Accept': 'application/json',
......@@ -47,8 +66,25 @@ export class ApiService {
});
}
// Calculate parameters for LSH + find candidates using LSH
async lshInitial(query): Promise<LshData> {
/**
* Get weights which will be applied to the LSH hash functions
*/
async getWeights(query: number[][], labels: {[index: number]: boolean}, weights: number[], hash_functions: number[][]): Promise<number[]> {
const response = await fetch('http://127.0.0.1:5000/weights', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: new Blob( [ JSON.stringify({query, labels, weights, hash_functions}) ], { type: 'text/plain' } )
});
return await response.json();
}
/**
* Do the first iteration of LSH and return important information
*/
async lshInitial(query: number[][]): Promise<LshData> {
const response = await fetch('http://127.0.0.1:5000/initialize', {
method: 'POST',
headers: {
......@@ -60,7 +96,9 @@ export class ApiService {
return await response.json();
}
// Find candidates using LSH with weights
/**
* Do another iteration of LSH, with weights, and return important information
*/
async lshUpdate(query, weights, parameters): Promise<LshData> {
const response = await fetch('http://127.0.0.1:5000/update', {
method: 'POST',
......@@ -73,21 +111,25 @@ export class ApiService {
return await response.json();
}
// Get query window based on windows labeled correct
async getQueryWindow(window): Promise<number[]> {
/**
* Get query window based on windows labeled correct
*/
async getQueryWindow(indices: number | {[index: number]: boolean}): Promise<number[][]> {
const response = await fetch('http://127.0.0.1:5000/query', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({window})
body: JSON.stringify({indices})
});
return await response.json();
}
// Get data of a window by indices
async getWindowByIndices(indices: number[]): Promise<number[][]> {
/**
* Get data of a window by indices
*/
async getWindowByIndices(indices: number[]): Promise<number[][][]> {
const response = await fetch('http://127.0.0.1:5000/window', {
method: 'POST',
headers: {
......@@ -99,14 +141,17 @@ export class ApiService {
return await response.json();
}
async getTableInfo(windows): Promise<TableInfoData> {
/**
* Get additional information for a given table
*/
async getTableInfo(table: number[][]): Promise<TableInfoData> {
const response = await fetch('http://127.0.0.1:5000/table-info', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({windows})
body: JSON.stringify({table})
});
return await response.json();
}
......
......@@ -19,6 +19,7 @@ import { ProgressViewComponent } from './progress-view/progress-view.component';
import { MainComponent } from './main/main.component';
import { MatProgressBarModule} from '@angular/material/progress-bar';
import {MatSliderModule} from '@angular/material/slider';
import { TrainingWindowComponent } from './training-window/training-window.component';
PlotlyModule.plotlyjs = PlotlyJS;
......@@ -33,6 +34,7 @@ PlotlyModule.plotlyjs = PlotlyJS;
QueryWindowComponent,
ProgressViewComponent,
MainComponent,
TrainingWindowComponent,
],
imports: [
BrowserModule,
......
......@@ -2,11 +2,12 @@
margin-right: 20px;
display: flex;
justify-content: center;
border-right: 1px solid;
border-bottom: 1px solid;
}
.subplot-container {
display: flex;
flex-wrap: wrap;
overflow-x: scroll;
width: 95%;
}
......
<div class="container">
<div *ngIf="show" class="subplot-container">
<div class="subplot-container">
<div class="subplot" *ngFor="let subplot of subplots">
<plotly-plot [data]="subplot.data" [layout]="subplot.layout"></plotly-plot>
<div class="button-holder">
......@@ -9,10 +9,6 @@
</div>
</div>
</div>
<div class="button-holder">
<!-- <button *ngIf="show" (click)="updateQuery()" class="train-button">Query</button>-->
<button *ngIf="show" (click)="train()" class="train-button">Train</button>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {StateService} from '../state.service';
@Component({
......@@ -10,86 +10,97 @@ export class LabelingWindowComponent implements OnInit {
public topk: number[];
public subplots = [];
public labels: boolean[] = [];
private k = 12;
private k = 5;
@Output() labelsOutput = new EventEmitter<boolean[]>();
constructor(private state: StateService) { }
ngOnInit(): void {
this.state.onNewTable.subscribe(() => this.showSamples());
}
async train() {
this.state.labels = Object.assign({}, this.state.labels, this.labels);
await this.state.getQueryWindow(this.state.labels);
await this.state.update();
}
async updateQuery() {
this.state.labels = Object.assign({}, this.state.labels, this.labels);
await this.state.getQueryWindow(this.state.labels);
this.state.onNewLshData.subscribe(() => this.showSamples());
}
public labelCorrect(index: number) {
this.labels[index] = true;
this.labelsOutput.emit(this.labels);
}
public labelUndefined(index: number) {
if (this.labels[index] !== undefined) {
delete this.labels[index];
this.labelsOutput.emit(this.labels);
}
}
public labelIncorrect(index: number) {
this.labels[index] = false;
this.labelsOutput.emit(this.labels);
}
async showSamples() {
this.topk = this.state.lshData.candidates
.filter((candidate) => this.state.labels[candidate] !== true)
.slice(0, this.k);
this.labels = [];
this.topk = this.state.lshData.samples;
this.subplots = [];
const values = await this.state.getWindow(this.topk);
this.topk.forEach((index, i) => {
this.subplots.push(
{
index,
data: [{
x: [...Array(values[i].length).keys()],
y: values[i],
type: 'line'
}],
layout: {
title: `Index: ${index.toString()}`,
hovermode: 'closest',
autosize: true,
margin: {
l: 30,
r: 30,
t: 30,
b: 0,
pad: 4
},
height: 150,
width: 300,
titlefont: {
size: 9
},
xaxis: {
showgrid: false,
zeroline: false,
showticklabels: false,
},
yaxis: {
zeroline: false,
showticklabels: false,
}
const values: number[][][] = await this.state.getWindow(this.topk);
for (const idx in this.topk) {
const window = values[idx];
const data = [];
window.forEach((channel: number[], index: number) => {
data.push({
x: [...Array(channel.length).keys()],
y: channel,
type: 'line',
xaxis: 'x',
yaxis: `y${index + 2}`,
});
});
const subplots = [];
window.forEach((channel: number[], index: number) => {
subplots.push([`xy${index + 2}`]);
});
const plot = {
index: this.topk[idx],
data: data,
layout: {
grid: {
rows: this.state.queryWindow.length,
columns: 1,
subplots: subplots,
},
showlegend: false,
title: `Index: ${this.topk[idx].toString()}`,
hovermode: 'closest',
autosize: true,
margin: {
l: 30,
r: 30,
t: 30,
b: 0,
pad: 4
},
height: 100 * values[0].length,
width: 300,
titlefont: {
size: 9
},
xaxis: {
showgrid: false,
zeroline: false,
showticklabels: false,
},
yaxis: {
zeroline: false,
showticklabels: false,
}
}
);
});
}
public get show() {
return !!this.state.lshData;
};
window.forEach((channel: number[], index: number) => {
plot.layout[`yaxis${index + 2}`] = {
zeroline: false,
showticklabels: false,
};
});
this.subplots.push(plot);
}
}
}
......@@ -20,7 +20,7 @@ export class LabelsComponent implements OnInit {
async createSubplots() {
this.goodLabels = [];
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) => {
const index = Number(key);
const plot =
......
......@@ -3,8 +3,7 @@
<app-overview-window style="z-index: 10"></app-overview-window>
<mat-tab-group animationDuration="0ms" (selectedTabChange)="changeTab($event)">
<mat-tab label="Training">
<app-labeling-window></app-labeling-window>
<app-table-overview></app-table-overview>
<app-training-window></app-training-window>
</mat-tab>
<mat-tab label="Labeled data">
<app-labels></app-labels>
......
<zingchart-angular [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>
import {Component, OnInit} from '@angular/core';
import {Component, OnInit, ViewChild} from '@angular/core';
import { StateService } from '../state.service';
import zingchart from 'zingchart/es6';
......@@ -8,12 +8,15 @@ import zingchart from 'zingchart/es6';
styleUrls: ['./overview-window.component.css']
})
export class OverviewWindowComponent implements OnInit {
@ViewChild('chart') chart;
public config;
public graphset = [];
public id = 'overview';
public markers = [];
public series = [];
public goodLabels = [];
public badLabels = [];
public candidateLabels = [];
public data;
public layout;
......@@ -23,98 +26,181 @@ export class OverviewWindowComponent implements OnInit {
async ngOnInit(): Promise<void> {
this.state.onNewData.subscribe(() => this.initializePlot());
this.state.onNewTable.subscribe(() => this.updatePlot());
// this.state.onNewTable.subscribe(() => this.updatePlot());
}
async initializePlot() {
this.state.queryWindow = undefined;
// this.debugClicked();
this.data = [];
for (let i = 0; i < this.state.rawData.values.length; i++) {
this.data.push([this.state.rawData.index[i], this.state.rawData.values[i]]);
}
this.series = [
{
type: 'line',
values: this.data,
text: 'Raw Values',
zIndex: 5,
marker: {
alpha: 0.0,
zIndex: 10
}
},
{
type: 'scatter',
values: [],
text: 'Good labels',
marker: {
backgroundColor: '#4caf50'
},
zIndex: 20,
},
{
type: 'scatter',
values: [],
text: 'Bad labels',
marker: {
backgroundColor: '#f44336'
},
zIndex: 20,
}];
this.config = {
type: 'mixed',
preview: {
height: '30px',
position: '0% 100%',
'auto-fit': true
},
plotarea: {
'margin-top': '10px',
'margin-bottom': '50%'
},
this.graphset.push({
id: 'preview',
type: "scatter",
x: 0,
y: 0,
scaleX: {
zooming: true,
minValue: 0,
maxValue: this.state.rawData[0].values.length,
zoomTo: [0, this.state.windowSize],
'auto-fit': true,
markers: this.markers
visible: false,
guide: {
visible: false
}
},
height: '30px',
scaleY: {
maxValue: 1,
minValue: -1,
visible: false,
guide: {
visible: false
}
},
'scale-y': {
'auto-fit': true
preview: {
x: 50,
y: 10,
height: '30px',
},
series: this.series
series: [
{
type: 'scatter',
values: [],
text: 'Good labels',
marker: {
backgroundColor: '#4caf50'
},
zIndex: 3,
},
{
type: 'scatter',
values: [],
text: 'Bad labels',
marker: {
backgroundColor: '#f44336'
},
zIndex: 2,
},
{
type: 'scatter',
values: [],
text: 'Candidates',
marker: {
backgroundColor: '#b1a343'
},
zIndex: 1,
}
]
});
// Initialize channels
this.state.rawData.forEach((channel, index) => {
const data = [];
for (let i = 0; i < channel.values.length; i++) {
data.push([i, channel.values[i]]);
}
this.graphset.push({
id: index,
x: 0,
y: `${75 * index + 50}px`,
type: 'line',
height: '50px',
scaleX: {
zooming: true,
zoomTo: [0, this.state.windowSize],
markers: []
},