diff options
author | Danijel Anđelković <adanijel99@gmail.com> | 2022-04-27 02:18:18 +0200 |
---|---|---|
committer | Danijel Anđelković <adanijel99@gmail.com> | 2022-04-27 02:18:18 +0200 |
commit | 0d2ba69f53f8f916d3758d532bddf0ed1cc69bda (patch) | |
tree | 52b48f27ad3972df6d099724968f1fa83bba444f /frontend/src/app | |
parent | aa254b6c3075805b000d774a98421aecbcb975a8 (diff) |
Ispravio graph da radi sa razlicitim brojem neurona za svaki sloj, uskladio sve korake na experiment strani, promenio stil navbara, dodao bottom dugmice u folder. Dodao responzivnost na nekim komponentama.
Diffstat (limited to 'frontend/src/app')
17 files changed, 573 insertions, 448 deletions
diff --git a/frontend/src/app/_data/Dataset.ts b/frontend/src/app/_data/Dataset.ts index 03060982..9d4b67a9 100644 --- a/frontend/src/app/_data/Dataset.ts +++ b/frontend/src/app/_data/Dataset.ts @@ -1,15 +1,17 @@ -export default class Dataset { +import { FolderFile } from "./FolderFile"; + +export default class Dataset extends FolderFile { _id: string = ''; constructor( - public name: string = 'Novi izvor podataka', + name: string = 'Novi izvor podataka', public description: string = '', public header: string[] = [], public fileId?: number, public extension: string = '.csv', public isPublic: boolean = false, public accessibleByLink: boolean = false, - public dateCreated: Date = new Date(), - public lastUpdated: Date = new Date(), + dateCreated: Date = new Date(), + lastUpdated: Date = new Date(), public uploaderId: string = '', public delimiter: string = '', public hasHeader: boolean = true, @@ -19,7 +21,9 @@ export default class Dataset { public nullRows: number = 0, public nullCols: number = 0, public preview: string[][] = [[]] - ) { } + ) { + super(name, dateCreated, lastUpdated); + } } export class ColumnInfo { diff --git a/frontend/src/app/_data/FolderFile.ts b/frontend/src/app/_data/FolderFile.ts new file mode 100644 index 00000000..a79eeac5 --- /dev/null +++ b/frontend/src/app/_data/FolderFile.ts @@ -0,0 +1,13 @@ +export class FolderFile { + constructor( + public name: string, + public dateCreated: Date, + public lastUpdated: Date + ) { } +} + + +export enum FolderType { + Dataset, + Model +}
\ No newline at end of file diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index a3b86bdf..c1f3d108 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -1,12 +1,13 @@ import { NgIf } from "@angular/common"; +import { FolderFile } from "./FolderFile"; -export default class Model { +export default class Model extends FolderFile { _id: string = ''; constructor( - public name: string = 'Novi model', + name: string = 'Novi model', public description: string = '', - public dateCreated: Date = new Date(), - public lastUpdated: Date = new Date(), + dateCreated: Date = new Date(), + lastUpdated: Date = new Date(), //public experimentId: string = '', // Neural net training settings @@ -15,57 +16,56 @@ export default class Model { public lossFunction: LossFunction = LossFunction.MeanSquaredError, public inputNeurons: number = 1, public hiddenLayers: number = 1, - public batchSize: number = 5, + public batchSize: BatchSize = BatchSize.O3, public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid, public uploaderId: string = '', public metrics: string[] = [], // TODO add to add-model form public epochs: number = 5, // TODO add to add-model form - public inputColNum:number=5, - public learningRate:LearningRate=LearningRate.LR1, - public layers:Layer[]=[new Layer()] + public inputColNum: number = 5, + public learningRate: LearningRate = LearningRate.LR1, + public layers: Layer[] = [new Layer()] - ) { } + ) { + super(name, dateCreated, lastUpdated); + } } -export class Layer{ +export class Layer { constructor( - public layerNumber:number=0, - public activationFunction:ActivationFunction=ActivationFunction.Sigmoid, - public neurons:number=1, - public regularisation:Regularisation=Regularisation.L1, - public regularisationRate:RegularisationRate=RegularisationRate.RR1, - - ) - {} - -} -export enum LearningRate{ - LR1='0.00001', - LR2='0.0001', - LR3='0.001', - LR4='0.003', - LR5='0.01', - LR6='0.03', - LR7='0.1', - LR8='0.3', - LR9='1', - LR10='3', - LR11='10', -} -export enum Regularisation{ - L1='l1', - L2='l2' -} -export enum RegularisationRate{ - RR1='0', - RR2='0.001', - RR3='0.003', - RR4='0.01', - RR5='0.03', - RR6='0.1', - RR7='0.3', - RR8='1', - RR9='3', - RR10='10', + public layerNumber: number = 0, + public activationFunction: ActivationFunction = ActivationFunction.Sigmoid, + public neurons: number = 1, + public regularisation: Regularisation = Regularisation.L1, + public regularisationRate: RegularisationRate = RegularisationRate.RR1, + ) { } +} +export enum LearningRate { + LR1 = '0.00001', + LR2 = '0.0001', + LR3 = '0.001', + LR4 = '0.003', + LR5 = '0.01', + LR6 = '0.03', + LR7 = '0.1', + LR8 = '0.3', + LR9 = '1', + LR10 = '3', + LR11 = '10', +} +export enum Regularisation { + L1 = 'l1', + L2 = 'l2' +} +export enum RegularisationRate { + RR1 = '0', + RR2 = '0.001', + RR3 = '0.003', + RR4 = '0.01', + RR5 = '0.03', + RR6 = '0.1', + RR7 = '0.3', + RR8 = '1', + RR9 = '3', + RR10 = '10', } export enum ProblemType { Regression = 'regresioni', @@ -198,4 +198,17 @@ export enum MetricsMultiClassification { Precision = 'precision_score', Recall = 'recall_score', F1 = 'f1_score', +} + +export enum BatchSize { + O1 = '2', + O2 = '4', + O3 = '8', + O4 = '16', + O5 = '32', + O6 = '64', + O7 = '128', + O8 = '256', + O9 = '512', + O10 = '1024' }
\ No newline at end of file diff --git a/frontend/src/app/_elements/folder/folder.component.css b/frontend/src/app/_elements/folder/folder.component.css index 3e865576..ce9b9fad 100644 --- a/frontend/src/app/_elements/folder/folder.component.css +++ b/frontend/src/app/_elements/folder/folder.component.css @@ -8,7 +8,7 @@ display: flex; flex-direction: row; align-items: flex-end; - height: 4rem; + height: 3.1rem; } #tabs>.folder-tab:not(:first-child) { @@ -83,16 +83,15 @@ #search-options { margin-left: auto; - margin-top: 7px; display: flex; flex-direction: row; align-items: center; + height: 100%; } #selected-content { background-color: var(--ns-bg-dark-50); width: 100%; - height: 36rem; /*backdrop-filter: blur(2px);*/ border-color: var(--ns-primary); border-style: solid; @@ -120,4 +119,72 @@ .rounded-bottom { border-top-right-radius: 0; border-top-left-radius: 0; +} + +.separator { + border-left-color: var(--ns-primary); + border-left-width: 1px; + border-left-style: solid; +} + +.list-view { + height: 100%; + overflow-y: auto; +} + +.list-item { + height: 3rem; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--ns-primary); +} + +.list-item:hover { + background-color: var(--ns-bg-dark-100); + box-shadow: 0px 3px 3px var(--ns-primary); +} + +.list-item:hover>.hover-hide { + display: none; +} + +.folder-inside { + width: 100%; + height: 40rem; + overflow-y: auto; +} + +.file-content { + width: 100%; + height: 100%; + position: relative; +} + +.file-bottom-buttons { + position: absolute; + bottom: 15px; + right: 15px; + display: flex; + flex-direction: row-reverse; +} + +.file-button { + position: relative; + color: var(--offwhite); + border-radius: 4px; + border: 1px solid var(--ns-primary); + margin: 5px; + padding: 5px; + cursor: pointer; + z-index: 1001; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} + +.file-button:hover { + background-color: var(--ns-primary); }
\ No newline at end of file diff --git a/frontend/src/app/_elements/folder/folder.component.html b/frontend/src/app/_elements/folder/folder.component.html index 95e99911..f0bc409a 100644 --- a/frontend/src/app/_elements/folder/folder.component.html +++ b/frontend/src/app/_elements/folder/folder.component.html @@ -1,4 +1,4 @@ -<div id="folder" style="width: 60rem;"> +<div id="folder"> <div id="tabs"> <div id="new-file-tab" class="folder-tab p-1 rounded-top" [style]="'z-index:' + newFileZIndex() + ' ;'" [ngClass]="{'selected-tab' : newFileSelected, 'hover-tab' : hoveringOverFileIndex == -2}"> <mat-icon class="text-offwhite">add</mat-icon> @@ -24,7 +24,6 @@ </div> <div id="search-options"> <div id="collapseFilters" class="collapse collapse-horizontal"> - <mat-icon class="text-offwhite ">timeline</mat-icon> Regresioni <mat-icon class="text-offwhite ">looks_two</mat-icon> @@ -32,19 +31,48 @@ <mat-icon class="text-offwhite ">auto_awesome_motion</mat-icon> Multiklasifikacioni </div> - <a class="tab-link p-1" data-bs-toggle="collapse" data-bs-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters"> + <button class="btn-clear icon-toggle" data-bs-toggle="collapse" data-bs-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters"> <mat-icon>filter_alt</mat-icon> - </a> + </button> <div id="collapseSort" class="collapse collapse-horizontal"> [sort options here TODO] </div> - <a class="tab-link p-1" data-bs-toggle="collapse" data-bs-target="#collapseSort" aria-expanded="false" aria-controls="collapseSort"> + <button class="btn-clear icon-toggle" data-bs-toggle="collapse" data-bs-target="#collapseSort" aria-expanded="false" aria-controls="collapseSort"> <mat-icon>sort</mat-icon> - </a> + </button> + <button class="btn-clear icon-toggle separator" [ngClass]="{'icon-toggle-on': listView}" (click)="toggleListView()"> + <mat-icon>view_list</mat-icon> + </button> + </div> + </div> + <!--{{fileToDisplay ? fileToDisplay.name : 'No file selected.'}} {{selectedFileIndex}} {{hoveringOverFileIndex}}--> + <div [ngSwitch]="listView" class="folder-inside"> + <div class="file-content" [ngSwitch]="type" *ngSwitchCase="false"> + <div class="file-bottom-buttons"> + <button class="btn-clear file-button" (click)="deleteFile()"> + <mat-icon>delete</mat-icon> + </button> + <button class="btn-clear file-button"> + <mat-icon>link</mat-icon> + </button> + <button class="btn-clear file-button"> + <mat-icon>zoom_out_map</mat-icon> + </button> + </div> + <app-form-model [model]="fileToDisplay" *ngSwitchCase="FolderType.Model"></app-form-model> + <app-form-dataset *ngSwitchCase="FolderType.Dataset"></app-form-dataset> + </div> + <div *ngSwitchCase="true" class="list-view"> + <div *ngFor="let file of filteredFiles; let i = index" class="list-item"> + <div class="mx-2"> + <a class="force-link" (click)="selectFile(i)">{{file.name}}</a> + </div> + <div class="mx-2 hover-hide"> + {{file.lastUpdated | date}} + </div> + </div> </div> </div> - <!-- {{fileToDisplay ? fileToDisplay.name : 'No file selected.'}} {{selectedFileIndex}} {{hoveringOverFileIndex}}--> - <app-form-dataset></app-form-dataset> </div> <div id="footer" [ngSwitch]="newFileSelected"> <button mat-button (click)="saveNewFile()" class="bottom-button text-offwhite rounded-bottom" *ngSwitchCase="true"> diff --git a/frontend/src/app/_elements/folder/folder.component.ts b/frontend/src/app/_elements/folder/folder.component.ts index 91565f3c..4bf964b6 100644 --- a/frontend/src/app/_elements/folder/folder.component.ts +++ b/frontend/src/app/_elements/folder/folder.component.ts @@ -1,5 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import Dataset from 'src/app/_data/Dataset'; +import { FolderFile, FolderType } from 'src/app/_data/FolderFile'; import Model from 'src/app/_data/Model'; @Component({ @@ -11,7 +12,7 @@ export class FolderComponent implements OnInit { @Input() folderName: string = 'Moji podaci'; - @Input() files!: (Dataset | Model)[] + @Input() files!: FolderFile[] newFile!: Dataset | Model; @@ -20,12 +21,12 @@ export class FolderComponent implements OnInit { newFileSelected: boolean = true; selectedFileIndex: number = -1; - selectedFile?: (Dataset | Model); + selectedFile?: FolderFile; hoveringOverFileIndex: number = -1; - fileToDisplay?: (Dataset | Model); + fileToDisplay?: FolderFile; - @Output() selectedFileChanged: EventEmitter<(Dataset | Model)> = new EventEmitter(); + @Output() selectedFileChanged: EventEmitter<FolderFile> = new EventEmitter(); @Output() okPressed: EventEmitter<string> = new EventEmitter(); searchTerm: string = ''; @@ -71,6 +72,7 @@ export class FolderComponent implements OnInit { this.fileToDisplay = this.newFile; this.selectedFile = this.newFile; this.newFileSelected = true; + this.listView = false; this.selectedFileChanged.emit(this.newFile); } @@ -79,6 +81,7 @@ export class FolderComponent implements OnInit { this.selectedFile = this.filteredFiles[index]; this.fileToDisplay = this.filteredFiles[index]; this.newFileSelected = false; + this.listView = false; this.selectedFileChanged.emit(this.selectedFile); } @@ -113,9 +116,10 @@ export class FolderComponent implements OnInit { clearSearchTerm() { this.searchTerm = ''; + this.searchTermsChanged(); } - filteredFiles: (Dataset | Model)[] = []; + filteredFiles: FolderFile[] = []; searchTermsChanged() { this.filteredFiles.length = 0; @@ -128,9 +132,21 @@ export class FolderComponent implements OnInit { } } } + + listView: boolean = false; + + toggleListView() { + this.listView = !this.listView; + } + + deleteFile() { + console.log('delete'); + } + + FolderType = FolderType; } -export enum FolderType { - Dataset, - Model -} +export enum Privacy { + Private, + Public +}
\ No newline at end of file diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.css b/frontend/src/app/_elements/form-dataset/form-dataset.component.css index 1a5bd03d..6b3e2bed 100644 --- a/frontend/src/app/_elements/form-dataset/form-dataset.component.css +++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.css @@ -1,28 +1,24 @@ +.folderBox { + width: 100%; + height: 100%; + position: relative; +} - - .folderBox - { - width: 100%; - height: 93%; - position: relative; - } - - .icon-display { +.icon-display { position: absolute; - transform: scale(4); - vertical-align: middle; - top: 40%; + top: 50%; left: 50%; - } - .bottomBar - { - position: absolute; - bottom: 0%; - left: 5%; - } + transform: translate(-50%, -50%) scale(4); +} + +.bottomBar { + position: absolute; + bottom: 0%; + left: 5%; +} - #bottomButton{ +#bottomButton { background-color: var(--ns-bg-dark-100); width: 10%; height: 65%; - }
\ No newline at end of file +}
\ No newline at end of file diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.html b/frontend/src/app/_elements/form-dataset/form-dataset.component.html index 615e3afe..50a33583 100644 --- a/frontend/src/app/_elements/form-dataset/form-dataset.component.html +++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.html @@ -1,8 +1,6 @@ <div class="folderBox"> - - <div > - <mat-icon class="icon-display">upload</mat-icon> - </div> + + <mat-icon class="icon-display">upload</mat-icon> <!-- <div class="px-5 mt-5"> @@ -10,64 +8,47 @@ </div> --> - <div class="bottomBar"> <div class="row"> - <div class="col-sm"> - <div role="group"> - <div class="row"> - <mat-form-field class="example-full-width" appearance="fill"> - <mat-label>Naziv</mat-label> - <input type="text" matInput value="titanik.csv" ><!--[formControl]="nameFormControl"--> - - <mat-error *ngIf="nameFormControl.hasError('required')"> - Naziv je <strong>obavezan</strong> - </mat-error> - </mat-form-field> - </div> + <div class="col-sm"> + <div role="group"> + <div class="row"> + <mat-form-field class="example-full-width" appearance="fill"> + <mat-label>Naziv</mat-label> + <input type="text" matInput value="titanik.csv"> + <!--[formControl]="nameFormControl"--> + + <mat-error *ngIf="nameFormControl.hasError('required')"> + Naziv je <strong>obavezan</strong> + </mat-error> + </mat-form-field> + </div> + </div> </div> - </div> - <div class="col-sm mb-3"> - - <input id="fileInput" class="form-control btn-lg" type="file" class="upload" (change)="changeListener($event)" accept=".csv"> - - </div> - <div class="col-sm"> - - <mat-form-field appearance="fill"> - <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (change)="update()"> - <mat-option *ngFor="let option of delimiterOptions"> - {{ option }} - </mat-option> - </mat-select> - </mat-form-field> - </div> - - <div class="col-sm"> + <div class="col-sm mb-3"> - <input type="checkbox" class="btn-check" id="checkboxAccessibleByLink" - [(ngModel)]="dataset.accessibleByLink" value=""> - <label class="btn btn-outline-primary" for="checkboxAccessibleByLink"> - <mat-icon>link</mat-icon> - </label> + <input id="fileInput" class="form-control btn-lg" type="file" class="upload" (change)="changeListener($event)" accept=".csv"> - </div> - <div class="col-sm"> - <button mat-button id="bottomButton"> - <mat-icon>zoom_in</mat-icon> - </button> - </div> + </div> + <div class="col-sm"> + + <mat-form-field appearance="fill"> + <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (change)="update()"> + <mat-option *ngFor="let option of delimiterOptions"> + {{ option }} + </mat-option> + </mat-select> + </mat-form-field> + </div> </div> - </div> + </div> <div class="btn-group" role="group" aria-label="Button group with nested dropdown"> - - </div> -<!-- + <!-- <div class="d-flex flex-row align-items-center justify-content-center w-100 my-2"> <button (click)="uploadDataset()" class="btn btn-lg col-4" style="background-color:#003459; color:white;">Dodaj izvor podataka</button> </div> diff --git a/frontend/src/app/_elements/form-model/form-model.component.css b/frontend/src/app/_elements/form-model/form-model.component.css index 051e23fc..c0ae9365 100644 --- a/frontend/src/app/_elements/form-model/form-model.component.css +++ b/frontend/src/app/_elements/form-model/form-model.component.css @@ -1,52 +1,114 @@ -#container{ - color:var(--offwhite); +#container { + color: var(--offwhite); } -mat-label{ + +mat-label { color: var(--offwhite) !important; } -select{ + +select { color: var(--offwhite) !important; } -mat-form-field{ + +mat-form-field { color: var(--offwhite) !important; padding: 0; + margin: 5px; + font-size: 12px; + width: 100%; } -hr{ - color:var(--ns-primary) 100%; - margin-bottom: 30px; - height: 2px; +hr { + color: var(--offwhite) !important; + margin-bottom: 30px; + ; } -.row{ - margin: 0; - padding: 0; -} -mat-icon{ - color: var(--ns-primary); -} -#rowhn{ - margin-bottom:-50px; - padding: 0; -} -.neuron{ - + +.neuron { text-align: justify; - border: 1px solid var(--ns-primary); + border: 1px solid white; border-radius: 5px; padding: 0; - color: white!important; + color: var(--offwhite) !important; background-color: var(--ns-bg-dark-100) !important; min-width: none; max-width: 12.5rem; - } -mat-form-field{ - font-size: 15px; -} -col-1{ + +col-1 { text-align: center; } -mat-icon{ - margin-right: 5px; - margin-left: -7px; + +.row { + margin: 0; + padding: 0; +} + +.ns-row { + width: 98%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0; + padding: 0; +} + +.ns-col { + flex-grow: 1; + padding: 2px; + margin-bottom: 0; + padding-bottom: 0; +} + +::ng-deep .mat-form-field-wrapper { + margin-bottom: -1.85em; +} + +.break-1, +.break-2 { + height: 1px; + width: 100%; +} + +@media screen and (min-width: 1200px) { + .break-1 { + display: none; + } +} + +@media screen and (min-width: 2175px) { + .break-2 { + display: none; + } +} + +#layers-control { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; +} + +#layers { + margin: 0; + padding: 0; + display: flex; + flex-direction: row; + overflow-x: auto; + overflow-wrap: break-word; + overflow-y: hidden; + width: 100%; +} + +.layer { + border: 1px solid var(--ns-primary); + border-radius: 4px; + margin: 5px; + padding: 3px; + width: 12rem; + height: 13rem; +} + +.layer>mat-form-field { + margin-left: 0; }
\ No newline at end of file diff --git a/frontend/src/app/_elements/form-model/form-model.component.html b/frontend/src/app/_elements/form-model/form-model.component.html index 6435b8d6..396d40c6 100644 --- a/frontend/src/app/_elements/form-model/form-model.component.html +++ b/frontend/src/app/_elements/form-model/form-model.component.html @@ -1,169 +1,153 @@ <div id="container"> - <div class="row"> - <div class="col-sm"> - <div class="row"> - <mat-form-field class="example-full-width" appearance="fill"> - <mat-label>Naziv</mat-label> - <input type="text" matInput [(ngModel)]="newModel.name"> - </mat-form-field> + <div class="ns-row"> + + <div class="ns-col"> + <mat-form-field class="example-full-width" appearance="fill"> + <mat-label>Naziv</mat-label> + <input type="text" matInput [(ngModel)]="newModel.name"> + </mat-form-field> </div> - <div class="row"> + <div class="ns-col"> <mat-form-field appearance="fill"> <mat-label>Tip problema</mat-label> - <mat-select [(ngModel)]="newModel.type"> - <mat-option - *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" - [value]="option"> - {{ optionName }} - </mat-option> + <mat-select [(ngModel)]="newModel.type"> + <mat-option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option"> + {{ optionName }} + </mat-option> </mat-select> - - </mat-form-field> + + </mat-form-field> </div> - </div> - <div class="col-sm"> - <div class="row"> + + <div class="break-1"></div> + + <div class="ns-col"> <mat-form-field appearance="fill"> <mat-label>Optimizacija</mat-label> - <mat-select [(ngModel)]="newModel.optimizer"> - <mat-option - *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)" - [value]="option"> - {{ optionName }} - </mat-option> + <mat-select [(ngModel)]="newModel.optimizer"> + <mat-option *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)" [value]="option"> + {{ optionName }} + </mat-option> </mat-select> - - </mat-form-field> + + </mat-form-field> </div> - <div class="row"> - <mat-form-field appearance="fill"> + <div class="ns-col"> + <mat-form-field appearance="fill"> <mat-label>Funkcija troška</mat-label> <mat-select [(ngModel)]="newModel.lossFunction"> - <mat-option - *ngFor="let option of Object.keys(LossFunction); let optionName of Object.values(LossFunction)" - [value]="option"> - {{ optionName }} - </mat-option> + <mat-option *ngFor="let option of Object.keys(LossFunction); let optionName of Object.values(LossFunction)" [value]="option"> + {{ optionName }} + </mat-option> </mat-select> - - </mat-form-field> + + </mat-form-field> </div> - </div> - <div class="col-sm"> - <div class="row"> - - <mat-form-field appearance="fill"> - <mat-label>Funkcija aktivacije izlaznog sloja</mat-label> - <mat-select name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction"> - <mat-option - *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" - [value]="option"> - {{ optionName }} - </mat-option> - </mat-select> - - </mat-form-field> - + + <div class="break-2"></div> + + <div class="ns-col"> + <mat-form-field appearance="fill"> + <mat-label>Funkcija aktivacije izlaznog sloja</mat-label> + <mat-select name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction"> + <mat-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option"> + {{ optionName }} + </mat-option> + </mat-select> + </mat-form-field> </div> - <div class="row"> - <mat-form-field appearance="fill"> + <div class="ns-col"> + <mat-form-field appearance="fill"> <mat-label>Stopa učenja</mat-label> - <mat-select [(ngModel)]="newModel.learningRate"> - <mat-option - *ngFor="let option of Object.keys(LearningRate); let optionName of Object.values(LearningRate)" - [value]="option"> - {{ optionName }} - </mat-option> + <mat-select [(ngModel)]="newModel.learningRate"> + <mat-option *ngFor="let option of Object.keys(LearningRate); let optionName of Object.values(LearningRate)" [value]="option"> + {{ optionName }} + </mat-option> </mat-select> - - </mat-form-field> - </div> - </div> - <div class="col"> - <div class="row"> - <div class="col-7">Broj Epoha</div> - <mat-icon (click)="addEpoch()">add_circle</mat-icon> - <div class="col-1">{{newModel.epochs}}</div> - <mat-icon (click)="removeEpoch()">remove_circle</mat-icon> + </mat-form-field> </div> - <br> - <br> - <div class="row"> - <div class="col-7">Broj Uzoraka Po Iteraciji</div> - <mat-icon (click)="addBatch()">add_circle</mat-icon> - <div class="col-1">{{newModel.batchSize}}</div> - <mat-icon (click)="removeBatch()">remove_circle</mat-icon> + + <div class="break-1"></div> + + <div class="ns-col"> + <mat-form-field appearance="fill"> + <mat-label>Broj epoha</mat-label> + <input type="number" matInput [(ngModel)]="newModel.epochs" min="1" max="1000"> + </mat-form-field> </div> - </div> - </div><!--kraj unosa parametara--> - <hr> - <div class="m-5"> - <app-graph [model]="newModel" [inputCols]="newModel.inputColNum"></app-graph> - <div class="row" id="rowhn"> - <div class="col-3"></div> - <div class="col-2">Broj Skrivenih Slojeva</div> - <div class="col-1"><mat-icon (click)="addLayer()" (ngModelChange)="updateGraph()">add_circle</mat-icon></div> - <div class="col-1">{{newModel.hiddenLayers}}</div> - <div class="col-1"><mat-icon (click)="removeLayer()" (ngModelChange)="updateGraph()">remove_circle</mat-icon></div> - </div> - </div> - <hr> - <div class="row" style="max-width:60rem ;"> - - <div class="col text-center" *ngFor="let item of numSequence(newModel.hiddenLayers); let i=index" > - {{item}} - <div class="neuron"> - <div style="text-align: center;"> - <label >Skriveni sloj {{i+1}}</label> - </div> - <div class="row" style="margin-bottom: -10px;"> + <div class="ns-col"> <mat-form-field appearance="fill"> - <mat-label>Aktivaciona funkcija</mat-label> - <mat-select [(ngModel)]="newModel.layers[i].activationFunction"> - <mat-option - *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" - [value]="option"> - {{ optionName }} - </mat-option> - </mat-select> - - </mat-form-field> - </div> - <div class="row" > - <div class="col-6" style="font-size: 13px;" >Broj čvorova</div> - <mat-icon (click)="addNeuron(i)">add_circle</mat-icon> - <div class="col-1">{{newModel.layers[i].neurons}}</div> - <mat-icon (click)="removeNeuron(i)">remove_circle</mat-icon> - + <mat-label>Broj uzoraka po iteraciji</mat-label> + + <mat-select matNativeControl required [(value)]="newModel.batchSize"> + <mat-option *ngFor="let option of Object.keys(BatchSize); let optionName of Object.values(BatchSize)" [value]="option">{{option}}</mat-option> + </mat-select> + </mat-form-field> </div> - <div class='row' style="margin-bottom: -7px;"> - <mat-form-field appearance="fill"> - <mat-label>Regularizacija</mat-label> - <mat-select [(ngModel)]="newModel.layers[i].regularisation"> - <mat-option - *ngFor="let option of Object.keys(Regularisation); let optionName of Object.values(Regularisation)" - [value]="option"> - {{ optionName }} - </mat-option> - </mat-select> - - </mat-form-field> - </div> - <div class="row" style="margin-bottom: -7px;"> - <mat-form-field appearance="fill"> - <mat-label>Stopa regularizacije</mat-label> - <mat-select [(ngModel)]="newModel.layers[i].regularisationRate"> - <mat-option - *ngFor="let option of Object.keys(RegularisationRate); let optionName of Object.values(RegularisationRate)" - [value]="option"> - {{ optionName }} - </mat-option> - </mat-select> - - </mat-form-field> - </div> + + </div> +</div> + + +<!--kraj unosa parametara--> +<hr> +<div class="m-2"> + <app-graph [model]="newModel" [inputCols]="newModel.inputColNum"></app-graph> + <div id="layers-control"> + <div>Broj Skrivenih Slojeva</div> + <button class="btn-clear btn-icon" (click)="addLayer()"> + <mat-icon>add</mat-icon> + </button> + <div>{{newModel.hiddenLayers}}</div> + <button class="btn-clear btn-icon" (click)="removeLayer()"> + <mat-icon>remove</mat-icon> + </button> + </div> +</div> +<hr> +<div id="layers"> + + <div class="layer" *ngFor="let item of newModel.layers; let i=index"> + <div class="text-center"> + #{{i+1}} + </div> + + <mat-form-field appearance="fill"> + <mat-label>Aktivaciona funkcija</mat-label> + <mat-select [(ngModel)]="newModel.layers[i].activationFunction"> + <mat-option *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" [value]="option"> + {{ optionName }} + </mat-option> + </mat-select> + </mat-form-field> + + <div class="d-flex flex-row align-items-center justify-content-center m-1"> + <div class="col-6" style="font-size: 13px;">Broj čvorova</div> + <button class="btn-clear btn-icon" (click)="addNeuron(i)"> + <mat-icon>add</mat-icon> + </button> + <div class="col-1">{{newModel.layers[i].neurons}}</div> + <button class="btn-clear btn-icon" (click)="removeNeuron(i)"> + <mat-icon>remove</mat-icon> + </button> </div> - <br> - </div> - - </div>
\ No newline at end of file + + <mat-form-field appearance="fill"> + <mat-label>Regularizacija</mat-label> + <mat-select [(ngModel)]="newModel.layers[i].regularisation"> + <mat-option *ngFor="let option of Object.keys(Regularisation); let optionName of Object.values(Regularisation)" [value]="option"> + {{ optionName }} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field appearance="fill"> + <mat-label>Stopa regularizacije</mat-label> + <mat-select [(ngModel)]="newModel.layers[i].regularisationRate"> + <mat-option *ngFor="let option of Object.keys(RegularisationRate); let optionName of Object.values(RegularisationRate)" [value]="option"> + {{ optionName }} + </mat-option> + </mat-select> + </mat-form-field> + </div> +</div>
\ No newline at end of file diff --git a/frontend/src/app/_elements/form-model/form-model.component.ts b/frontend/src/app/_elements/form-model/form-model.component.ts index c3c73b3e..c29fd0bb 100644 --- a/frontend/src/app/_elements/form-model/form-model.component.ts +++ b/frontend/src/app/_elements/form-model/form-model.component.ts @@ -1,37 +1,36 @@ -import { Component, OnInit ,Input, ViewChild, Output, EventEmitter} from '@angular/core'; -import {FormControl, Validators} from '@angular/forms'; +import { Component, OnInit, Input, ViewChild, Output, EventEmitter, AfterViewInit } from '@angular/core'; +import { FormControl, Validators } from '@angular/forms'; import Shared from 'src/app/Shared'; import Experiment from 'src/app/_data/Experiment'; -import Model, {Layer, ActivationFunction, LossFunction,LearningRate, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType ,Regularisation,RegularisationRate} from 'src/app/_data/Model'; +import Model, { Layer, ActivationFunction, LossFunction, LearningRate, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType, Regularisation, RegularisationRate, BatchSize } from 'src/app/_data/Model'; import { GraphComponent } from '../graph/graph.component'; -import {FormGroupDirective, NgForm} from '@angular/forms'; -import {ErrorStateMatcher} from '@angular/material/core'; +import { FormGroupDirective, NgForm } from '@angular/forms'; +import { ErrorStateMatcher } from '@angular/material/core'; + @Component({ selector: 'app-form-model', templateUrl: './form-model.component.html', styleUrls: ['./form-model.component.css'] }) -export class FormModelComponent implements OnInit { +export class FormModelComponent implements AfterViewInit { @ViewChild(GraphComponent) graph!: GraphComponent; @Input() forExperiment?: Experiment; @Output() selectedModelChangeEvent = new EventEmitter<Model>(); - constructor() { - this.newModel.epochs=1; - this.newModel.batchSize=1; -} - - ngOnInit(): void { + constructor() { } + + ngAfterViewInit(): void { } + selectFormControl = new FormControl('', Validators.required); nameFormControl = new FormControl('', [Validators.required, Validators.email]); - selectTypeFormControl=new FormControl('', Validators.required); - selectOptFormControl=new FormControl('', Validators.required); - selectLFFormControl=new FormControl('', Validators.required); - selectLRFormControl=new FormControl('', Validators.required); - selectEpochFormControl=new FormControl('', Validators.required); - selectAFFormControl=new FormControl('', Validators.required); - selectBSFormControl=new FormControl('', Validators.required); + selectTypeFormControl = new FormControl('', Validators.required); + selectOptFormControl = new FormControl('', Validators.required); + selectLFFormControl = new FormControl('', Validators.required); + selectLRFormControl = new FormControl('', Validators.required); + selectEpochFormControl = new FormControl('', Validators.required); + selectAFFormControl = new FormControl('', Validators.required); + selectBSFormControl = new FormControl('', Validators.required); selectActivationFormControl = new FormControl('', Validators.required); selectRegularisationFormControl = new FormControl('', Validators.required); selectRRateFormControl = new FormControl('', Validators.required); @@ -43,92 +42,44 @@ export class FormModelComponent implements OnInit { ProblemType = ProblemType; ActivationFunction = ActivationFunction; - RegularisationRate=RegularisationRate; - Regularisation=Regularisation; + RegularisationRate = RegularisationRate; + Regularisation = Regularisation; metrics: any = Metrics; LossFunction = LossFunction; Optimizer = Optimizer; + BatchSize = BatchSize; Object = Object; document = document; shared = Shared; - LearningRate=LearningRate; - Layer=Layer; - + LearningRate = LearningRate; + Layer = Layer; + term: string = ""; selectedMetrics = []; lossFunction: any = LossFunction; showMyModels: boolean = true; - - hiddenLayers=[]; - - - updateGraph() { + console.log(this.newModel.layers); this.graph.update(); } - removeLayer(){ - if(this.newModel.hiddenLayers>1) - { - this.newModel.layers.splice(this.newModel.layers.length-1,1); - this.newModel.hiddenLayers-=1; + + removeLayer() { + if (this.newModel.hiddenLayers > 1) { + this.newModel.layers.splice(this.newModel.layers.length - 1, 1); + this.newModel.hiddenLayers -= 1; this.updateGraph(); } } - addLayer(){ - if(this.newModel.hiddenLayers<12) - { + addLayer() { + if (this.newModel.hiddenLayers < 128) { this.newModel.layers.push(new Layer(this.newModel.layers.length)); - this.newModel.hiddenLayers+=1; + this.newModel.hiddenLayers += 1; this.updateGraph(); } - - } - removeBatch(){ - if(this.newModel.batchSize>1) - { - this.newModel.batchSize=this.newModel.batchSize/2; - } - else - { - this.newModel.batchSize=this.newModel.batchSize; - } - - } - addBatch(){ - if(this.newModel.batchSize<600) - { - this.newModel.batchSize=this.newModel.batchSize*2; - } - else - { - this.newModel.batchSize=this.newModel.batchSize; - - } - } - removeEpoch(){ - if(this.newModel.epochs>1) - { - this.newModel.epochs=this.newModel.epochs-1; - } - else - { - this.newModel.epochs=this.newModel.epochs; - } - - } - addEpoch(){ - if(this.newModel.epochs<100) - { - this.newModel.epochs=this.newModel.epochs+1; - } - else - { - this.newModel.epochs=this.newModel.epochs; - - } + } /* setNeurons() @@ -140,18 +91,16 @@ export class FormModelComponent implements OnInit { numSequence(n: number): Array<number> { return Array(n); } - - removeNeuron(index:number){ - if(this.newModel.layers[index].neurons>1) - { - this.newModel.layers[index].neurons-=1; + + removeNeuron(index: number) { + if (this.newModel.layers[index].neurons > 1) { + this.newModel.layers[index].neurons -= 1; this.updateGraph(); } } - addNeuron(index:number){ - if(this.newModel.layers[index].neurons<100) - { - this.newModel.layers[index].neurons+=1; + addNeuron(index: number) { + if (this.newModel.layers[index].neurons < 100) { + this.newModel.layers[index].neurons += 1; this.updateGraph(); } } diff --git a/frontend/src/app/_elements/graph/graph.component.html b/frontend/src/app/_elements/graph/graph.component.html index 92e9df38..b8220115 100644 --- a/frontend/src/app/_elements/graph/graph.component.html +++ b/frontend/src/app/_elements/graph/graph.component.html @@ -1,3 +1,3 @@ -<div #graphWrapper class="w-100" style="height: 16rem;"> +<div #graphWrapper class="w-100" style="height: 14rem;"> <canvas #graphCanvas></canvas> </div>
\ No newline at end of file diff --git a/frontend/src/app/_elements/graph/graph.component.ts b/frontend/src/app/_elements/graph/graph.component.ts index c20d3dd7..5dec3152 100644 --- a/frontend/src/app/_elements/graph/graph.component.ts +++ b/frontend/src/app/_elements/graph/graph.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; import Dataset from 'src/app/_data/Dataset'; -import Model,{Layer} from 'src/app/_data/Model'; +import Model, { Layer } from 'src/app/_data/Model'; @Component({ selector: 'app-graph', @@ -22,11 +22,11 @@ export class GraphComponent implements AfterViewInit { @Input() lineColor: string = '#00a8e8'; @Input() nodeColor: string = '#222277'; @Input() borderColor: string = '#00a8e8'; - @Input() inputNodeColor: string = '#ffdd11'; - @Input() outputNodeColor: string = '#44ee22'; + @Input() inputNodeColor: string = '#00a8e8'; + @Input() outputNodeColor: string = '#dfd7d7'; - private ctx?: CanvasRenderingContext2D; - @Input() inputNeurons: number=1; + private ctx!: CanvasRenderingContext2D; + @Input() inputNeurons: number = 1; constructor() { } @@ -51,7 +51,7 @@ export class GraphComponent implements AfterViewInit { let inputNodeIndex = 0; const inputLayer: Node[] = []; while (inputNodeIndex < this.inputCols) { - const x = 0.5 / (this.inputNeurons + 2); + const x = 0.5 / (this.model!.hiddenLayers + 2); const y = (inputNodeIndex + 0.5) / this.inputCols; const node = new Node(x, y, this.inputNodeColor); inputLayer.push(node); @@ -63,9 +63,9 @@ export class GraphComponent implements AfterViewInit { while (layerIndex < this.model!.hiddenLayers + 1) { const newLayer: Node[] = []; let nodeIndex = 0; - while (nodeIndex < this.model!.layers[layerIndex].neurons) { + while (nodeIndex < this.model!.layers[layerIndex - 1].neurons) { const x = (layerIndex + 0.5) / (this.model!.hiddenLayers + 2); - const y = (nodeIndex + 0.5) / this.model!.layers[layerIndex].neurons; + const y = (nodeIndex + 0.5) / this.model!.layers[layerIndex - 1].neurons; const node = new Node(x, y, this.nodeColor); newLayer.push(node); nodeIndex += 1; @@ -81,7 +81,7 @@ export class GraphComponent implements AfterViewInit { } draw() { - this.ctx!.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height); + this.ctx.clearRect(0, 0, this.canvas.nativeElement.width, this.canvas.nativeElement.height); let index = 0; while (index < this.layers!.length - 1) { @@ -101,22 +101,22 @@ export class GraphComponent implements AfterViewInit { } drawLine(node1: Node, node2: Node) { - this.ctx!.strokeStyle = this.lineColor; - this.ctx!.lineWidth = this.lineThickness; - this.ctx!.beginPath(); - this.ctx!.moveTo(node1.x * this.width, node1.y * this.height); - this.ctx!.lineTo(node2.x * this.width, node2.y * this.height); - this.ctx!.stroke(); + this.ctx.strokeStyle = this.lineColor; + this.ctx.lineWidth = this.lineThickness; + this.ctx.beginPath(); + this.ctx.moveTo(node1.x * this.width, node1.y * this.height); + this.ctx.lineTo(node2.x * this.width, node2.y * this.height); + this.ctx.stroke(); } drawNode(node: Node) { - this.ctx!.fillStyle = node.color; - this.ctx!.strokeStyle = this.borderColor; - this.ctx!.lineWidth = this.lineThickness; - this.ctx!.beginPath(); - this.ctx!.arc(node.x * this.width, node.y * this.height, this.nodeRadius, 0, 2 * Math.PI); - this.ctx!.fill(); - this.ctx!.stroke(); + this.ctx.fillStyle = node.color; + this.ctx.strokeStyle = this.borderColor; + this.ctx.lineWidth = this.lineThickness; + this.ctx.beginPath(); + this.ctx.arc(node.x * this.width, node.y * this.height, this.nodeRadius, 0, 2 * Math.PI); + this.ctx.fill(); + this.ctx.stroke(); } width = 200; diff --git a/frontend/src/app/_elements/navbar/navbar.component.html b/frontend/src/app/_elements/navbar/navbar.component.html index 09d83bd1..9a54a9de 100644 --- a/frontend/src/app/_elements/navbar/navbar.component.html +++ b/frontend/src/app/_elements/navbar/navbar.component.html @@ -1,4 +1,4 @@ -<header class="bg-dark text-white"> +<header class="text-offwhite" style="background-color: #002b49;"> <div class="container"> <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"> <a routerLink="" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none"> @@ -6,10 +6,10 @@ </a> <ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0"> - <li><a routerLink="" class="nav-link px-2" [class]="(currentUrl === '') ? 'text-secondary' : 'text-white'">Početna</a></li> - <li><a routerLink="experiment" class="nav-link px-2" [class]="(currentUrl === '/experiment') ? 'text-secondary' : 'text-white'">Napravi eksperiment</a> + <li><a routerLink="" class="nav-link px-2" [class]="(currentUrl === '') ? 'text-primary' : 'text-offwhite'">Početna</a></li> + <li><a routerLink="experiment" class="nav-link px-2" [class]="(currentUrl === '/experiment') ? 'text-primary' : 'text-offwhite'">Napravi eksperiment</a> </li> - <li><a routerLink="archive" class="nav-link px-2" [class]="(currentUrl === '/archive') ? 'text-secondary' : 'text-white'">Arhiva</a> + <li><a routerLink="archive" class="nav-link px-2" [class]="(currentUrl === '/archive') ? 'text-primary' : 'text-offwhite'">Arhiva</a> </li> </ul> diff --git a/frontend/src/app/_pages/experiment/experiment.component.css b/frontend/src/app/_pages/experiment/experiment.component.css index 2fde8e7f..aca0562a 100644 --- a/frontend/src/app/_pages/experiment/experiment.component.css +++ b/frontend/src/app/_pages/experiment/experiment.component.css @@ -46,4 +46,10 @@ mat-stepper { flex-direction: row; justify-content: center; align-items: center; +} + +.step-content-inside { + width: 90%; + height: 90%; + overflow-y: auto; }
\ No newline at end of file diff --git a/frontend/src/app/_pages/experiment/experiment.component.html b/frontend/src/app/_pages/experiment/experiment.component.html index 6200270c..1606adf5 100644 --- a/frontend/src/app/_pages/experiment/experiment.component.html +++ b/frontend/src/app/_pages/experiment/experiment.component.html @@ -22,16 +22,19 @@ </div> <div #stepsContainer class="steps-container"> <div #steps id="step_1" class="step-content"> - <app-folder (okPressed)="goToPage(1)"></app-folder> + <div class="step-content-inside"> + <app-folder [type]="FolderType.Dataset" (okPressed)="goToPage(1)"></app-folder> + </div> </div> <div #steps id="step_2" class="step-content"> - <div class="mx-3" style="overflow-x: auto;"> - <app-column-table></app-column-table> - </div> + <div class="step-content-inside"> + <app-column-table></app-column-table> + </div> </div> <div #steps id="step_3" class="step-content"> - - <app-form-model></app-form-model> + <div class="step-content-inside"> + <app-folder [type]="FolderType.Model" (okPressed)="goToPage(0)"></app-folder> + </div> </div> </div> </div>
\ No newline at end of file diff --git a/frontend/src/app/_pages/experiment/experiment.component.ts b/frontend/src/app/_pages/experiment/experiment.component.ts index ad0f1df2..d80ba70f 100644 --- a/frontend/src/app/_pages/experiment/experiment.component.ts +++ b/frontend/src/app/_pages/experiment/experiment.component.ts @@ -2,6 +2,7 @@ import { AfterViewInit, Component, ElementRef, ViewChild, ViewChildren } from '@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { MatStepper } from '@angular/material/stepper'; import Shared from 'src/app/Shared'; +import { FolderType } from 'src/app/_data/FolderFile'; @Component({ selector: 'app-experiment', @@ -86,4 +87,6 @@ export class ExperimentComponent implements AfterViewInit { scrolling: boolean = false; + FolderType = FolderType; + } |