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'; import { Injectable } from '@angular/core';
export interface RawData { export interface RawData {
index: string[]; index: string[][];
values: number[]; values: number[][];
} }
export interface LshData { export interface LshData {
candidates: number[]; candidates: number[][][];
distances: number[]; distances: number[][][];
hash_functions: number[];// number[][][][]; average_candidates: number[];
average_distances: number[];
tables: {[bucket: string]: number[]}[];
average_table: {[bucket: string]: number[]};
samples: 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[][];
} }
export interface Parameters {
windowsize: number;
hashsize: number;
tablesize: number;
stepsize: number;
}
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
/**
* This service acts as the interface between the client and server side.
*/
export class ApiService { export class ApiService {
constructor() { } 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'); const response = await fetch('http://127.0.0.1:5000/read-data');
return await response.json(); 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 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', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
...@@ -47,8 +66,25 @@ export class ApiService { ...@@ -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', { const response = await fetch('http://127.0.0.1:5000/initialize', {
method: 'POST', method: 'POST',
headers: { headers: {
...@@ -60,7 +96,9 @@ export class ApiService { ...@@ -60,7 +96,9 @@ export class ApiService {
return await response.json(); 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> { async lshUpdate(query, weights, parameters): Promise<LshData> {
const response = await fetch('http://127.0.0.1:5000/update', { const response = await fetch('http://127.0.0.1:5000/update', {
method: 'POST', method: 'POST',
...@@ -73,21 +111,25 @@ export class ApiService { ...@@ -73,21 +111,25 @@ export class ApiService {
return await response.json(); 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', { const response = await fetch('http://127.0.0.1:5000/query', {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({window}) body: JSON.stringify({indices})
}); });
return await response.json(); 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', { const response = await fetch('http://127.0.0.1:5000/window', {
method: 'POST', method: 'POST',
headers: { headers: {
...@@ -99,14 +141,17 @@ export class ApiService { ...@@ -99,14 +141,17 @@ export class ApiService {
return await response.json(); 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', { const response = await fetch('http://127.0.0.1:5000/table-info', {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({windows}) body: JSON.stringify({table})
}); });
return await response.json(); return await response.json();
} }
......
...@@ -19,6 +19,7 @@ import { ProgressViewComponent } from './progress-view/progress-view.component'; ...@@ -19,6 +19,7 @@ import { ProgressViewComponent } from './progress-view/progress-view.component';
import { MainComponent } from './main/main.component'; import { MainComponent } from './main/main.component';
import { MatProgressBarModule} from '@angular/material/progress-bar'; import { MatProgressBarModule} from '@angular/material/progress-bar';
import {MatSliderModule} from '@angular/material/slider'; import {MatSliderModule} from '@angular/material/slider';
import { TrainingWindowComponent } from './training-window/training-window.component';
PlotlyModule.plotlyjs = PlotlyJS; PlotlyModule.plotlyjs = PlotlyJS;
...@@ -33,6 +34,7 @@ PlotlyModule.plotlyjs = PlotlyJS; ...@@ -33,6 +34,7 @@ PlotlyModule.plotlyjs = PlotlyJS;
QueryWindowComponent, QueryWindowComponent,
ProgressViewComponent, ProgressViewComponent,
MainComponent, MainComponent,
TrainingWindowComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
......
...@@ -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%;
} }
......
<div class="container"> <div class="container">
<div *ngIf="show" class="subplot-container"> <div class="subplot-container">
<div class="subplot" *ngFor="let subplot of subplots"> <div class="subplot" *ngFor="let subplot of subplots">
<plotly-plot [data]="subplot.data" [layout]="subplot.layout"></plotly-plot> <plotly-plot [data]="subplot.data" [layout]="subplot.layout"></plotly-plot>
<div class="button-holder"> <div class="button-holder">
...@@ -9,10 +9,6 @@ ...@@ -9,10 +9,6 @@
</div> </div>
</div> </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> </div>
import { Component, OnInit } from '@angular/core'; import {Component, EventEmitter, OnInit, Output} from '@angular/core';
import {StateService} from '../state.service'; import {StateService} from '../state.service';
@Component({ @Component({
...@@ -10,86 +10,97 @@ export class LabelingWindowComponent implements OnInit { ...@@ -10,86 +10,97 @@ export class LabelingWindowComponent implements OnInit {
public topk: number[]; public topk: number[];
public subplots = []; public subplots = [];
public labels: boolean[] = []; public labels: boolean[] = [];
private k = 12; private k = 5;
@Output() labelsOutput = new EventEmitter<boolean[]>();
constructor(private state: StateService) { } constructor(private state: StateService) { }
ngOnInit(): void { ngOnInit(): void {
this.state.onNewTable.subscribe(() => this.showSamples()); this.state.onNewLshData.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);
} }
public labelCorrect(index: number) { public labelCorrect(index: number) {
this.labels[index] = true; this.labels[index] = true;
this.labelsOutput.emit(this.labels);
} }
public labelUndefined(index: number) { public labelUndefined(index: number) {
if (this.labels[index] !== undefined) { if (this.labels[index] !== undefined) {
delete this.labels[index]; delete this.labels[index];
this.labelsOutput.emit(this.labels);
} }
} }
public labelIncorrect(index: number) { public labelIncorrect(index: number) {
this.labels[index] = false; this.labels[index] = false;
this.labelsOutput.emit(this.labels);
} }
async showSamples() { async showSamples() {
this.topk = this.state.lshData.candidates this.labels = [];
.filter((candidate) => this.state.labels[candidate] !== true) this.topk = this.state.lshData.samples;
.slice(0, this.k);
this.subplots = []; this.subplots = [];
const values = await this.state.getWindow(this.topk); const values: number[][][] = await this.state.getWindow(this.topk);
this.topk.forEach((index, i) => { for (const idx in this.topk) {
this.subplots.push( const window = values[idx];
{ const data = [];
index, window.forEach((channel: number[], index: number) => {
data: [{ data.push({
x: [...Array(values[i].length).keys()], x: [...Array(channel.length).keys()],
y: values[i], y: channel,
type: 'line' type: 'line',
}], xaxis: 'x',
layout: { yaxis: `y${index + 2}`,
title: `Index: ${index.toString()}`, });
hovermode: 'closest', });
autosize: true, const subplots = [];
margin: { window.forEach((channel: number[], index: number) => {
l: 30, subplots.push([`xy${index + 2}`]);
r: 30, });
t: 30, const plot = {
b: 0, index: this.topk[idx],
pad: 4 data: data,
}, layout: {
height: 150, grid: {
width: 300, rows: this.state.queryWindow.length,
titlefont: { columns: 1,
size: 9 subplots: subplots,
}, },
xaxis: { showlegend: false,
showgrid: false, title: `Index: ${this.topk[idx].toString()}`,
zeroline: false, hovermode: 'closest',
showticklabels: false, autosize: true,
}, margin: {
yaxis: { l: 30,
zeroline: false, r: 30,
showticklabels: false, 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,
} }
} }
); };
}); window.forEach((channel: number[], index: number) => {
} plot.layout[`yaxis${index + 2}`] = {
zeroline: false,
public get show() { showticklabels: false,
return !!this.state.lshData; };
});
this.subplots.push(plot);
}
} }
} }
...@@ -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,7 @@ ...@@ -3,8 +3,7 @@
<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-training-window></app-training-window>
<app-table-overview></app-table-overview>
</mat-tab> </mat-tab>
<mat-tab label="Labeled data"> <mat-tab label="Labeled data">
<app-labels></app-labels> <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 { StateService } from '../state.service';
import zingchart from 'zingchart/es6'; import zingchart from 'zingchart/es6';
...@@ -8,12 +8,15 @@ import zingchart from 'zingchart/es6'; ...@@ -8,12 +8,15 @@ import zingchart from 'zingchart/es6';
styleUrls: ['./overview-window.component.css'] styleUrls: ['./overview-window.component.css']
}) })
export class OverviewWindowComponent implements OnInit { export class OverviewWindowComponent implements OnInit {
@ViewChild('chart') chart;
public config; public config;
public graphset = [];
public id = 'overview'; public id = 'overview';
public markers = []; public markers = [];
public series = []; public series = [];
public goodLabels = []; public goodLabels = [];
public badLabels = []; public badLabels = [];
public candidateLabels = [];
public data; public data;
public layout; public layout;
...@@ -23,98 +26,181 @@ export class OverviewWindowComponent implements OnInit { ...@@ -23,98 +26,181 @@ export class OverviewWindowComponent implements OnInit {
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.state.onNewData.subscribe(() => this.initializePlot()); this.state.onNewData.subscribe(() => this.initializePlot());
this.state.onNewTable.subscribe(() => this.updatePlot()); // this.state.onNewTable.subscribe(() => this.updatePlot());
} }
async initializePlot() { async initializePlot() {
this.state.queryWindow = undefined; this.state.queryWindow = undefined;
// this.debugClicked(); // this.debugClicked();
this.data = []; this.graphset.push({
for (let i = 0; i < this.state.rawData.values.length; i++) { id: 'preview',
this.data.push([this.state.rawData.index[i], this.state.rawData.values[i]]); type: "scatter",
} x: 0,
this.series = [ y: 0,
{
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'
<