diff options
author | Ognjen Cirkovic <ciraboxkg@gmail.com> | 2022-03-22 15:04:36 +0000 |
---|---|---|
committer | Ognjen Cirkovic <ciraboxkg@gmail.com> | 2022-03-22 15:04:36 +0000 |
commit | 012fb19a54f4d55a6e4cc73227f738f64539cf04 (patch) | |
tree | 57b3de84ad41037e8c7b1403dba4a5bad24a4752 /frontend | |
parent | b4f0cd025a86c68a5c35a58e62c22b7cedf3d8b5 (diff) | |
parent | 31642f68564e67175301235546b74baf56ac5882 (diff) |
Merge branch 'dev' into 'Privremeno-cuvanje-podataka'
# Conflicts:
# backend/api/api/Controllers/ModelController.cs
Diffstat (limited to 'frontend')
26 files changed, 589 insertions, 68 deletions
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5b23f3d2..0333f749 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -24,9 +24,11 @@ "@ng-bootstrap/ng-bootstrap": "^12.0.0", "@popperjs/core": "^2.10.2", "bootstrap": "^5.1.3", + "chart.js": "^3.7.1", "csv-parser": "^3.0.0", "mdb-angular-ui-kit": "^2.0.0", "ng-uikit-pro-standard": "^1.0.0", + "ng2-charts": "^3.0.8", "ngx-cookie-service": "^13.1.2", "ngx-csv-parser": "^0.0.7", "rxjs": "~7.5.0", @@ -3792,6 +3794,11 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/chart.js": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", + "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -7376,6 +7383,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -7949,6 +7961,21 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/ng2-charts": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-3.0.8.tgz", + "integrity": "sha512-ELlpN0b/IJO4ka/P2sFBKeng3bV7XOQuh40f0J5hx9UveWPaSxOYQAOiGxV7BN2VSnKq6GRkjRvqTrcQPyJYww==", + "dependencies": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=11.0.0", + "@angular/core": ">=11.0.0", + "chart.js": "^3.4.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/ngx-cookie-service": { "version": "13.1.2", "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-13.1.2.tgz", @@ -14259,6 +14286,11 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chart.js": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz", + "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==" + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -16856,6 +16888,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -17286,6 +17323,15 @@ } } }, + "ng2-charts": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-3.0.8.tgz", + "integrity": "sha512-ELlpN0b/IJO4ka/P2sFBKeng3bV7XOQuh40f0J5hx9UveWPaSxOYQAOiGxV7BN2VSnKq6GRkjRvqTrcQPyJYww==", + "requires": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + } + }, "ngx-cookie-service": { "version": "13.1.2", "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-13.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 01cdf462..c3f0310e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,9 +26,11 @@ "@ng-bootstrap/ng-bootstrap": "^12.0.0", "@popperjs/core": "^2.10.2", "bootstrap": "^5.1.3", + "chart.js": "^3.7.1", "csv-parser": "^3.0.0", "mdb-angular-ui-kit": "^2.0.0", "ng-uikit-pro-standard": "^1.0.0", + "ng2-charts": "^3.0.8", "ngx-cookie-service": "^13.1.2", "ngx-csv-parser": "^0.0.7", "rxjs": "~7.5.0", @@ -49,4 +51,4 @@ "karma-jasmine-html-reporter": "~1.7.0", "typescript": "~4.5.2" } -}
\ No newline at end of file +} diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index a891c10c..0768a374 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -12,7 +12,7 @@ export default class Model { public columnToPredict: string = '', public randomOrder: boolean = true, public randomTestSet: boolean = true, - public randomTestSetDistribution: number = 0.10, //0.1-0.9 (10% - 90%) + public randomTestSetDistribution: number = 0.1, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U // Neural net training settings public type: ANNType = ANNType.FullyConnected, @@ -39,21 +39,61 @@ export enum ANNType { // removeOutliers export enum Encoding { Label = 'label', - OneHot = 'one hot' + OneHot = 'one hot', + BackwardDifference = 'backward difference', + BaseN = 'baseN', + Binary = 'binary', + CatBoost = 'cat boost', + Count = 'count', + GLMM = 'glmm', + Hashing = 'hashing', + Helmert = 'helmert', + JamesStein = 'james stein', + LeaveOneOut = 'leave one out', + MEstimate = 'MEstimate', + Ordinal = 'ordinal', + Sum = 'sum', + Polynomial = 'polynomial', + Target = 'target', + WOE = 'woe', + Quantile = 'quantile' } export enum ActivationFunction { + // linear + Binary_Step = 'binaryStep', + Linear = 'linear', + // non-linear Relu = 'relu', + Leaky_Relu = 'leakyRelu', + Parameterised_Relu = 'parameterisedRelu', + Exponential_Linear_Unit = 'exponentialLinearUnit', + Swish = 'swish', Sigmoid = 'sigmoid', Tanh = 'tanh', - Linear = 'linear' + Softmax = 'softmax' } export enum LossFunction { + // binary classification loss functions BinaryCrossEntropy = 'binary_crossentropy', - MeanSquaredError = 'mean_squared_error' + HingeLoss = 'hinge_loss', + // multi-class classiication loss functions + CategoricalCrossEntropy = 'categorical_crossentropy', + KLDivergence = 'kullback_leibler_divergence', + // regression loss functions + MeanSquaredError = 'mean_squared_error', + MeanAbsoluteError = 'mean_absolute_error', + HuberLoss = 'Huber', } export enum Optimizer { - Adam = 'adam' + Adam = 'Adam', + Adadelta = 'Adadelta', + Adagrad = 'Adagrad', + Ftrl = 'Ftrl', + Nadam = 'Nadam', + SGD = 'SGD', + SGDMomentum = 'SGDMomentum', + RMSprop = 'RMSprop' }
\ No newline at end of file diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.html b/frontend/src/app/_elements/dataset-load/dataset-load.component.html index fcec6ec3..76fc40e2 100644 --- a/frontend/src/app/_elements/dataset-load/dataset-load.component.html +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.html @@ -30,7 +30,7 @@ </div> </div> - <div class="table-responsive"> + <div class="table-responsive" *ngIf="hasInput"> <table *ngIf="csvRecords.length > 0 && hasHeader" class="table table-bordered table-light mt-4"> <thead> <tr> @@ -53,7 +53,7 @@ </table> </div> - <div *ngIf="csvRecords.length > 0" id="info"> + <div *ngIf="csvRecords.length > 0 && hasInput" id="info"> . . . <br> {{rowsNumber}} x {{colsNumber}} </div> diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts index 913592eb..bccf13b7 100644 --- a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts +++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts @@ -16,7 +16,7 @@ export class DatasetLoadComponent { hasHeader: boolean = true; - slice: string = ""; + hasInput: boolean = false; csvRecords: any[] = []; files: File[] = []; @@ -33,6 +33,15 @@ export class DatasetLoadComponent { changeListener($event: any): void { this.files = $event.srcElement.files; + if (this.files.length == 0 || this.files[0] == null) { + //console.log("NEMA FAJLA"); + //this.loaded.emit("not loaded"); + this.hasInput = false; + return; + } + else + this.hasInput = true; + console.log(this.files); this.update(); } diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.html b/frontend/src/app/_elements/item-dataset/item-dataset.component.html index cf39a125..46840cdd 100644 --- a/frontend/src/app/_elements/item-dataset/item-dataset.component.html +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.html @@ -2,7 +2,7 @@ <div class="card-header"> {{dataset.name}} </div> - <div class="card-body"> + <div class="card-body overflow-hidden"> <p class="card-text"> {{dataset.description}} </p> diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.html b/frontend/src/app/_modals/login-modal/login-modal.component.html index d694ea58..d7836848 100644 --- a/frontend/src/app/_modals/login-modal/login-modal.component.html +++ b/frontend/src/app/_modals/login-modal/login-modal.component.html @@ -20,12 +20,12 @@ <input [(ngModel)]="password" name="password" type="password" id="password" class="form-control form-control" placeholder="Unesite lozinku..." /> </div> - - <div class="text-center text-lg-start mt-5 pt-2"> - <p *ngIf="wrongCreds" class="small fw-bold mt-2 pt-1 mb-0 text-danger">Lozinka ili e-mail su pogrešni - </p> - </div> </form> + + <div class="text-center text-lg-start mt-5"> + <p *ngIf="wrongCreds" class="small fw-bold text-danger text-center">Unesite ispravan e-mail i lozinku.</p> + </div> + <div class="col-md-12 d-flex justify-content-center"> <button type="button" class="btn btn-lg" style="color:white; background-color: #003459; margin-right: 10px;" (click)="doLogin()">Prijavite se</button> <button type="button" class="btn btn-lg btn-outline-secondary" data-bs-dismiss="modal" (click)="resetData()">Odustanite</button> diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.ts b/frontend/src/app/_modals/login-modal/login-modal.component.ts index d17d7017..1b634c9a 100644 --- a/frontend/src/app/_modals/login-modal/login-modal.component.ts +++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts @@ -13,7 +13,7 @@ export class LoginModalComponent implements OnInit { username: string = ''; password: string = ''; - public wrongCreds: boolean = false; //RAZMOTRITI + wrongCreds: boolean = false; constructor( private authService: AuthService, @@ -26,17 +26,26 @@ export class LoginModalComponent implements OnInit { doLogin() { if (this.username.length > 0 && this.password.length > 0) { - this.authService.login(this.username, this.password).subscribe((response) => { //ako nisu ok podaci, ne ide hide nego mora opet da ukucava!!!!podesi + this.authService.login(this.username, this.password).subscribe((response) => { console.log(response); - this.authService.authenticate(response); - (<HTMLSelectElement>document.getElementById('closeButton')).click(); - }, error => { - console.warn(error); //NETACNI PODACI + + if (response == "Username doesn't exist" || response == "Wrong password") { + this.wrongCreds = true; + this.password = ''; + } + else { + this.authService.authenticate(response); + (<HTMLSelectElement>document.getElementById('closeButton')).click(); + } }); } - + else { + this.wrongCreds = true; + this.password = ''; + } } resetData() { + this.wrongCreds = false; this.username = ''; this.password = ''; } diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.html b/frontend/src/app/_modals/register-modal/register-modal.component.html index 7098c040..68025a46 100644 --- a/frontend/src/app/_modals/register-modal/register-modal.component.html +++ b/frontend/src/app/_modals/register-modal/register-modal.component.html @@ -4,7 +4,7 @@ <div class="modal-dialog modal-dialog-centered modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header" style="background-color: #003459;"> - <button type="button" class="btn-close" data-bs-dismiss="modal" style="background-color: white;" + <button id="closeButtonReg" type="button" class="btn-close" data-bs-dismiss="modal" style="background-color: white;" aria-label="Close" (click)="resetData()"></button> </div> <div class="modal-body" style="color:#003459"> diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.ts b/frontend/src/app/_modals/register-modal/register-modal.component.ts index c02a4e1a..c045f1ce 100644 --- a/frontend/src/app/_modals/register-modal/register-modal.component.ts +++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts @@ -136,15 +136,21 @@ export class RegisterModalComponent implements OnInit { .subscribe( (response) => { console.log(response); - if (response === 'User added') { - this.resetData(); - (<HTMLSelectElement>document.getElementById('linkToLoginModal')).click(); + if (response == 'User added') { + //nakon sto je registrovan, nek bude ulogovan + this.authService.login(this.username, this.pass1).subscribe((response) => { + + this.authService.authenticate(response); + console.log("close button"); + (<HTMLSelectElement>document.getElementById('closeButtonReg')).click(); + //(<HTMLSelectElement>document.getElementById('linkToLoginModal')).click(); + }, (error) => console.warn(error)); } - else if (response === 'Email Already Exists') { + else if (response == 'Email Already Exists') { alert('Nalog sa unetim email-om već postoji!'); (<HTMLSelectElement>document.getElementById('email')).focus(); } - else if (response === 'Username Already Exists') { + else if (response == 'Username Already Exists') { alert('Nalog sa unetim korisničkim imenom već postoji!'); (<HTMLSelectElement>document.getElementById('username-register')).focus(); } diff --git a/frontend/src/app/_pages/add-model/add-model.component.css b/frontend/src/app/_pages/add-model/add-model.component.css index 4bf569cc..6d961287 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.css +++ b/frontend/src/app/_pages/add-model/add-model.component.css @@ -15,4 +15,21 @@ #wrapper { color: #003459; +} + +.btnType1 { + background-color: #003459; + color: white; +} +.btnType2 { + background-color: white; + color: #003459; + border-color: #003459; +} +.selectedDatasetClass { + /*border-color: 2px solid #003459;*/ + background-color: lightblue; +} +ul li:hover { + background-color: lightblue; }
\ No newline at end of file diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html index c6f21f1e..33066f80 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.html +++ b/frontend/src/app/_pages/add-model/add-model.component.html @@ -6,7 +6,7 @@ <div id="container" class="container p-5" style="background-color: white; min-height: 100%;"> - <div class="form-group row mb-4 d-flex justify-content-center"> + <div class="form-group row mt-3 mb-2 d-flex justify-content-center"> <!--justify-content-center--> <h2 class="col-2"> Nov model: </h2> <div class="col-3"> @@ -26,22 +26,87 @@ </div> </div> - <div class="mt-5 justify-content-center"> - <h2>Izvor podataka:</h2> - <app-dataset-load id="dataset" (loaded)="datasetLoaded = true"></app-dataset-load> + <div class="py-3 pr-5 justify-content-center"> + + <div class="col-12 d-flex my-5"> + <h2 class="">Izvor podataka:</h2> + <div class="col-1"> + </div> + <button type="button" id="btnMyDataset" class="btn" (click)="viewMyDatasetsForm()" + [ngClass]="{'btnType1': showMyDatasets, 'btnType2': !showMyDatasets}"> + Izaberite dataset iz kolekcije + </button> + <h3 class="mt-3 mx-3">ili</h3> + <button type="button" id="btnNewDataset" class="btn" (click)="viewNewDatasetForm()" + [ngClass]="{'btnType1': !showMyDatasets, 'btnType2': showMyDatasets}"> + Dodajte novi dataset + </button> + </div> + + <!-- POSTOJECI ILI NOVI DATASET --> + + <!-- POSTOJECI --> + <div class="px-5"> + <div *ngIf="showMyDatasets" class="overflow-auto" style="max-height: 500px;"> + <ul class="list-group"> + <li class="list-group-item p-3" *ngFor="let dataset of myDatasets" [ngClass]="{'selectedDatasetClass': this.selectedDataset == dataset}"> + <app-item-dataset name="usersDataset" [dataset]="dataset" (click)="selectThisDataset(dataset)"></app-item-dataset> + </li> + </ul> + </div> + </div> + + <!-- NOVI --> + <app-dataset-load *ngIf="!showMyDatasets" id="dataset" (loaded)="datasetLoaded = true"></app-dataset-load> </div> - <div *ngIf="datasetLoaded"> - <div *ngIf="datasetLoadComponent" class="row"> + + <!-- ULAZNE/IZLAZNE KOLONE - POSTOJECI DATASET --> + <div *ngIf="showMyDatasets && this.selectedDataset" class="mt-4"> + <h2 class="text-center"> + Izabrali ste dataset: <span style="color: #003459; font-weight: bold">{{this.selectedDataset.name}}</span> + </h2> + <div class="row mt-5"> + <div class="col d-flex justify-content-center"> + <h3>Izaberite ulazne kolone:</h3> + <div id="divInputs" class="form-check mt-2"> + <br> + <div *ngFor="let item of this.selectedDataset.header; let i = index"> + <input class="form-check-input" type="checkbox" value="{{item}}" + id="cb_{{item}}" name="cbsExisting" checked [disabled]="this.selectedOutputColumnVal == item"> + <label class="form-check-label" for="cb_{{item}}"> + {{item}} + </label> + </div> + </div> + </div> + <div class="col d-flex justify-content-left"> + <h3>Izaberite izlaznu kolonu:</h3> + <div id="divOutputs" class="form-check mt-2"> + <br> + <div *ngFor="let item of this.selectedDataset.header; let i = index"> + <input class="form-check-input" type="radio" value="{{item}}" + id="rb_{{item}}" name="rbsExisting" (change)="this.selectedOutputColumnVal = item"> + <label class="form-check-label" for="rb_{{item}}"> + {{item}} + </label> + </div> + </div> + </div> + </div> + </div> + + + <!-- ULAZNE/IZLAZNE KOLONE - NOVI DATASET--> + <div *ngIf="!showMyDatasets && datasetLoaded"> + <div *ngIf="datasetLoadComponent && datasetLoadComponent.files[0]" class="row"> <div class="col d-flex justify-content-center"> <h3>Izaberite ulazne kolone:</h3> <div id="divInputs" class="form-check mt-2"> <br> <div *ngFor="let item of datasetLoadComponent.dataset.header; let i = index"> - <input *ngIf="i == 0" class="form-check-input" type="checkbox" value="{{item}}" - id="cb_{{item}}" name="cbs" checked> - <input *ngIf="i != 0" class="form-check-input" type="checkbox" value="{{item}}" - id="cb_{{item}}" name="cbs"> + <input class="form-check-input" type="checkbox" value="{{item}}" + id="cb_{{item}}" name="cbsNew" checked [disabled]="this.selectedOutputColumnVal == item"> <label class="form-check-label" for="cb_{{item}}"> {{item}} </label> @@ -53,10 +118,8 @@ <div id="divOutputs" class="form-check mt-2"> <br> <div *ngFor="let item of datasetLoadComponent.dataset.header; let i = index"> - <input *ngIf="i == 0" class="form-check-input" type="radio" value="{{item}}" - id="rb_{{item}}" name="rbs" checked> - <input *ngIf="i != 0" class="form-check-input" type="radio" value="{{item}}" - id="rb_{{item}}" name="rbs"> + <input class="form-check-input" type="radio" value="{{item}}" + id="rb_{{item}}" name="rbsNew" (change)="this.selectedOutputColumnVal = item"> <label class="form-check-label" for="rb_{{item}}"> {{item}} </label> @@ -193,15 +256,10 @@ <div class="col-1"> </div> <div class="col-5"> - <label for="type" class="form-check-label">Podela test skupa: - <input class="form-check-input" type="checkbox" [checked]="newModel.randomTestSet" + <label for="splitYesNo" class="form-check-label">Podela test skupa: + <input id="splitYesNo" class="form-check-input" type="checkbox" [checked]="newModel.randomTestSet" (change)="newModel.randomTestSet = !newModel.randomTestSet"> - </label> - test - <mat-slider min="0.1" max="0.9" step="0.1" value="0.2" name="randomTestSetDistribution" thumbLabel - [disabled]="!newModel.randomTestSet" [(ngModel)]="newModel.randomTestSetDistribution"> - </mat-slider> - trening + </label> </div> <div class="col"> </div> @@ -224,9 +282,14 @@ </option> </select> </div> - <div class="col"> + <div class="col-1"> </div> - <div class="col"> + <div class="col-2"> + <label for="percentage" class="form-label">Procenat podataka koji se uzima za trening skup:</label> + </div> + <div class="col-1"> + <input id="percentage" type="number" class="form-control" min="10" max="90" step="10" value="90" [(ngModel)]="tempTestSetDistribution" + [disabled] = "!newModel.randomTestSet"> </div> </div> @@ -247,7 +310,14 @@ </option> </select> </div> + <div class="col-1"> + </div> <div class="col"> + trening + <mat-slider min="10" max="90" step="10" value="10" name="randomTestSetDistribution" thumbLabel + [disabled]="!newModel.randomTestSet" [(ngModel)]="tempTestSetDistribution"> + </mat-slider> + test </div> <div class="col"> </div> diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts index a4cabb82..7bfb7204 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.ts +++ b/frontend/src/app/_pages/add-model/add-model.component.ts @@ -1,10 +1,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { Observable, of } from 'rxjs'; import Model from 'src/app/_data/Model'; import { ANNType, Encoding, ActivationFunction, LossFunction, Optimizer } from 'src/app/_data/Model'; import { DatasetLoadComponent } from 'src/app/_elements/dataset-load/dataset-load.component'; import { ModelsService } from 'src/app/_services/models.service'; import shared from 'src/app/Shared'; +import Dataset from 'src/app/_data/Dataset'; @Component({ @@ -27,63 +27,145 @@ export class AddModelComponent implements OnInit { Object = Object; shared = shared; + selectedOutputColumnVal: string = ''; + + showMyDatasets: boolean = true; + myDatasets?: Dataset[]; + existingDatasetSelected: boolean = false; + selectedDataset?: Dataset; + + tempTestSetDistribution: number = 90; + constructor(private models: ModelsService) { this.newModel = new Model(); + + this.models.getMyDatasets().subscribe((datasets) => { + this.myDatasets = datasets; + }); } ngOnInit(): void { + (<HTMLInputElement>document.getElementById("btnMyDataset")).focus(); + } + + viewMyDatasetsForm() { + this.showMyDatasets = true; + this.resetSelectedDataset(); + this.datasetLoaded = false; + this.resetCbsAndRbs(); + } + viewNewDatasetForm() { + this.showMyDatasets = false; + this.resetSelectedDataset(); + this.resetCbsAndRbs(); } addModel() { - this.saveModel(false); //trajno cuvanje + if (!this.showMyDatasets) + this.saveModelWithNewDataset(); + else + this.saveModelWithExistingDataset(); } trainModel() { - this.saveModel(true).subscribe((modelId: any) => { + this.saveModelWithNewDataset().subscribe((modelId: any) => { if (modelId) this.models.trainModel(modelId); }); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad } - saveModel(temporary: boolean): any { + saveModelWithNewDataset(): any { + this.getCheckedInputCols(); this.getCheckedOutputCol(); + if (this.validationInputsOutput()) { console.log('ADD MODEL: STEP 1 - UPLOAD FILE'); if (this.datasetLoadComponent) { + this.models.uploadData(this.datasetLoadComponent.files[0]).subscribe((file) => { console.log('ADD MODEL: STEP 2 - ADD DATASET WITH FILE ID ' + file._id); if (this.datasetLoadComponent) { this.datasetLoadComponent.dataset.fileId = file._id; this.datasetLoadComponent.dataset.username = shared.username; + this.models.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => { console.log('ADD MODEL: STEP 3 - ADD MODEL WITH DATASET ID ', dataset._id); this.newModel.datasetId = dataset._id; + + //da se doda taj dataset u listu postojecih, da bude izabran + this.refreshMyDatasetList(); + this.showMyDatasets = true; + this.selectThisDataset(dataset); + + this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10; + this.tempTestSetDistribution = 90; this.newModel.username = shared.username; + this.models.addModel(this.newModel).subscribe((response) => { console.log('ADD MODEL: DONE! REPLY:\n', response); - }); - }); - } + }, (error) => { + alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); + }); //kraj addModel subscribe + }, (error) => { + alert("Dataset sa unetim nazivom već postoji u Vašoj kolekciji.\nIzmenite naziv ili iskoristite postojeći dataset."); + }); //kraj addDataset subscribe + } //kraj treceg ifa + }, (error) => { + //alert("greska uploadData"); + }); //kraj uploadData subscribe + + } //kraj drugog ifa + } //kraj prvog ifa + } + + saveModelWithExistingDataset(): any { + + if (this.selectedDataset) { //dataset je izabran + this.getCheckedInputCols(); + this.getCheckedOutputCol(); + + if (this.validationInputsOutput()) { + this.newModel.datasetId = this.selectedDataset._id; + + this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10; + this.tempTestSetDistribution = 90; + this.newModel.username = shared.username; + + this.models.addModel(this.newModel).subscribe((response) => { + console.log('ADD MODEL: DONE! REPLY:\n', response); + }, (error) => { + alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); }); } } + else { + alert("Molimo Vas da izaberete neki dataset iz kolekcije."); + } } getCheckedInputCols() { this.newModel.inputColumns = []; - let checkboxes = document.getElementsByName("cbs"); - + let checkboxes: any; + if (this.showMyDatasets) + checkboxes = document.getElementsByName("cbsExisting"); + else + checkboxes = document.getElementsByName("cbsNew"); + for (let i = 0; i < checkboxes.length; i++) { let thatCb = <HTMLInputElement>checkboxes[i]; - if (thatCb.checked) + if (thatCb.checked == true && thatCb.disabled == false) this.newModel.inputColumns.push(thatCb.value); } //console.log(this.checkedInputCols); } getCheckedOutputCol() { this.newModel.columnToPredict = ''; - let radiobuttons = document.getElementsByName("rbs"); + let radiobuttons: any; + if (this.showMyDatasets) + radiobuttons = document.getElementsByName("rbsExisting"); + else + radiobuttons = document.getElementsByName("rbsNew"); for (let i = 0; i < radiobuttons.length; i++) { let thatRb = <HTMLInputElement>radiobuttons[i]; @@ -95,8 +177,16 @@ export class AddModelComponent implements OnInit { //console.log(this.checkedOutputCol); } validationInputsOutput(): boolean { - if (this.newModel.inputColumns.length == 0) { - alert("Molimo Vas da izaberete ulaznu kolonu/kolone za mrežu.") + if (this.newModel.inputColumns.length == 0 && this.newModel.columnToPredict == '') { + alert("Molimo Vas da izaberete ulazne i izlazne kolone za mrežu."); + return false; + } + else if (this.newModel.inputColumns.length == 0) { + alert("Molimo Vas da izaberete ulaznu kolonu/kolone za mrežu."); + return false; + } + else if (this.newModel.columnToPredict == '') { + alert("Molimo Vas da izaberete izlaznu kolonu za mrežu."); return false; } for (let i = 0; i < this.newModel.inputColumns.length; i++) { @@ -109,4 +199,65 @@ export class AddModelComponent implements OnInit { return true; } + selectThisDataset(dataset: Dataset) { + this.selectedDataset = dataset; + this.existingDatasetSelected = true; + + /*let datasets = document.getElementsByClassName("usersDataset") as HTMLCollection; + for (let i = 0; i < datasets.length; i++) { + if (datasets[i]._id == dataset._id) + }*/ + + this.resetCbsAndRbs(); + } + + resetSelectedDataset(): boolean { + this.existingDatasetSelected = false; + this.selectedDataset = undefined; + return true; + } + resetCbsAndRbs(): boolean { + this.uncheckRbs(); + this.checkAllCbs(); + return true; + } + checkAllCbs() { + let checkboxes: any; + //if (this.showMyDatasets) + checkboxes = document.getElementsByName("cbsExisting"); + //else + //checkboxes = document.getElementsByName("cbsNew"); + + for (let i = 0; i < checkboxes.length; i++) { + (<HTMLInputElement>checkboxes[i]).checked = true; + (<HTMLInputElement>checkboxes[i]).disabled = false; + } + + checkboxes = document.getElementsByName("cbsNew"); + for (let i = 0; i < checkboxes.length; i++) { + (<HTMLInputElement>checkboxes[i]).checked = true; + (<HTMLInputElement>checkboxes[i]).disabled = false; + } + } + uncheckRbs() { + this.selectedOutputColumnVal = ''; + let radiobuttons: any; + //if (this.showMyDatasets) + radiobuttons = document.getElementsByName("rbsExisting"); + //else + //radiobuttons = document.getElementsByName("rbsNew"); + + for (let i = 0; i < radiobuttons.length; i++) + (<HTMLInputElement>radiobuttons[i]).checked = false; + radiobuttons = document.getElementsByName("rbsNew"); + for (let i = 0; i < radiobuttons.length; i++) + (<HTMLInputElement>radiobuttons[i]).checked = false; + } + + refreshMyDatasetList() { + this.models.getMyDatasets().subscribe((datasets) => { + this.myDatasets = datasets; + }); + } + } diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts index 8299016b..30d63956 100644 --- a/frontend/src/app/_services/models.service.ts +++ b/frontend/src/app/_services/models.service.ts @@ -38,4 +38,8 @@ export class ModelsService { trainModel(modelId: string): Observable<any> { return this.http.post(`${API_SETTINGS.apiURL}/model/train`, modelId, { headers: this.authService.authHeader() }); } + + getMyDatasets(): Observable<Dataset[]> { + return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() });//responsetype text da l treba?? + } } diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 35e5adb1..24828a06 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,4 +1,6 @@ <app-navbar></app-navbar> <div class="container h-100"> <router-outlet></router-outlet> -</div>
\ No newline at end of file + <app-barchart></app-barchart> + <app-scatterchart></app-scatterchart> +</div> diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 5aa405fb..7f076421 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -6,6 +6,8 @@ import { HttpClientModule } from '@angular/common/http'; import { MatSliderModule } from '@angular/material/slider'; import { MatIconModule } from '@angular/material/icon'; +import {NgChartsModule} from 'ng2-charts'; + import { AppComponent } from './app.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { DatasetLoadComponent } from './_elements/dataset-load/dataset-load.component'; @@ -29,6 +31,8 @@ import { MyModelsComponent } from './_pages/my-models/my-models.component'; import { BrowseDatasetsComponent } from './_pages/browse-datasets/browse-datasets.component'; import { BrowsePredictorsComponent } from './_pages/browse-predictors/browse-predictors.component'; import { PredictComponent } from './_pages/predict/predict.component'; +import { ScatterchartComponent } from './scatterchart/scatterchart.component'; +import { BarchartComponent } from './barchart/barchart.component'; @NgModule({ declarations: [ @@ -49,7 +53,9 @@ import { PredictComponent } from './_pages/predict/predict.component'; MyModelsComponent, BrowseDatasetsComponent, BrowsePredictorsComponent, - PredictComponent + PredictComponent, + ScatterchartComponent, + BarchartComponent ], imports: [ BrowserModule, @@ -61,7 +67,8 @@ import { PredictComponent } from './_pages/predict/predict.component'; MaterialModule, ReactiveFormsModule, MatSliderModule, - MatIconModule + MatIconModule, + NgChartsModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/src/app/barchart/barchart.component.css b/frontend/src/app/barchart/barchart.component.css new file mode 100644 index 00000000..c3634c9f --- /dev/null +++ b/frontend/src/app/barchart/barchart.component.css @@ -0,0 +1,6 @@ +#divBarChart{ + background-color: beige; + display: block; + width: 400px; + height: 200px; +} diff --git a/frontend/src/app/barchart/barchart.component.html b/frontend/src/app/barchart/barchart.component.html new file mode 100644 index 00000000..48b7bd3e --- /dev/null +++ b/frontend/src/app/barchart/barchart.component.html @@ -0,0 +1,4 @@ +<p>Bar chart:</p> +<div id="divBarChart"> + <canvas id="Barchart"> </canvas> +</div>
\ No newline at end of file diff --git a/frontend/src/app/barchart/barchart.component.spec.ts b/frontend/src/app/barchart/barchart.component.spec.ts new file mode 100644 index 00000000..8b346d1c --- /dev/null +++ b/frontend/src/app/barchart/barchart.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BarchartComponent } from './barchart.component'; + +describe('BarchartComponent', () => { + let component: BarchartComponent; + let fixture: ComponentFixture<BarchartComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ BarchartComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(BarchartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/barchart/barchart.component.ts b/frontend/src/app/barchart/barchart.component.ts new file mode 100644 index 00000000..def64b7d --- /dev/null +++ b/frontend/src/app/barchart/barchart.component.ts @@ -0,0 +1,54 @@ +import { Component, OnInit } from '@angular/core'; +import {Chart} from 'node_modules/chart.js'; + +@Component({ + selector: 'app-barchart', + templateUrl: './barchart.component.html', + styleUrls: ['./barchart.component.css'] +}) +export class BarchartComponent implements OnInit { + + constructor() { } + + ngOnInit(){ + const myChart = new Chart("Barchart", { + type: 'bar', + data: { + labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], + datasets: [{ + label: 'Number of Votes', + data: [12, 19, 3, 5, 2, 3], + backgroundColor: [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)' + ], + borderColor: [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)' + ], + borderWidth: 1 + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + + + }); + + + } + +} diff --git a/frontend/src/app/scatterchart/scatterchart.component.css b/frontend/src/app/scatterchart/scatterchart.component.css new file mode 100644 index 00000000..5735217e --- /dev/null +++ b/frontend/src/app/scatterchart/scatterchart.component.css @@ -0,0 +1,6 @@ +#divScatterChart{ + background-color: beige; + display: block; + width: 400px; + height: 200px; +}
\ No newline at end of file diff --git a/frontend/src/app/scatterchart/scatterchart.component.html b/frontend/src/app/scatterchart/scatterchart.component.html new file mode 100644 index 00000000..2b30fe1f --- /dev/null +++ b/frontend/src/app/scatterchart/scatterchart.component.html @@ -0,0 +1,4 @@ +<p>Scatter chart:</p> +<div id="divScatterChart"> + <canvas id="ScatterCharts"> </canvas> +</div>
\ No newline at end of file diff --git a/frontend/src/app/scatterchart/scatterchart.component.spec.ts b/frontend/src/app/scatterchart/scatterchart.component.spec.ts new file mode 100644 index 00000000..1db81051 --- /dev/null +++ b/frontend/src/app/scatterchart/scatterchart.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ScatterchartComponent } from './scatterchart.component'; + +describe('ScatterchartComponent', () => { + let component: ScatterchartComponent; + let fixture: ComponentFixture<ScatterchartComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ScatterchartComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ScatterchartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/scatterchart/scatterchart.component.ts b/frontend/src/app/scatterchart/scatterchart.component.ts new file mode 100644 index 00000000..1da88fe7 --- /dev/null +++ b/frontend/src/app/scatterchart/scatterchart.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; +import {Chart} from 'node_modules/chart.js'; + +@Component({ + selector: 'app-scatterchart', + templateUrl: './scatterchart.component.html', + styleUrls: ['./scatterchart.component.css'] +}) +export class ScatterchartComponent implements OnInit { + + constructor() { } + + ngOnInit(){ + const myChart = new Chart("ScatterCharts", { + type: 'scatter', + data: { + datasets: [{ + label: 'Scatter Example:', + data: [{x: 1, y: 11}, {x:2, y:12}, {x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}, {x: 1, y: 3}, {x: 3, y: 4}, {x: 4, y: 6}, {x: 6, y: 9}], + backgroundColor: 'rgb(255, 99, 132)' + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + } +} diff --git a/frontend/src/index.html b/frontend/src/index.html index b3b6eb54..0079969e 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -12,5 +12,6 @@ </head> <body class="mat-typography"> <app-root></app-root> + <script src="node_modules/chart.js/src/chart.js"></script> </body> </html> diff --git a/frontend/src/styles.css b/frontend/src/styles.css index d37ab6f1..5a30802b 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1,3 +1,4 @@ +@import '~bootstrap/dist/css/bootstrap.min.css'; body { background-image: url('/assets/images/add_model_background.jpg'); }
\ No newline at end of file |