diff options
author | Danijel Anđelković <adanijel99@gmail.com> | 2022-05-03 22:44:25 +0200 |
---|---|---|
committer | Danijel Anđelković <adanijel99@gmail.com> | 2022-05-03 22:44:25 +0200 |
commit | e09ca08e9a09f4073d15a5341a746d5356da353c (patch) | |
tree | 53d2c0aa3b4d9564f4cfaebd348af917c4e4374b /frontend/src/app | |
parent | 8462d0080036650a9e79a379a06ae395ccacf0c8 (diff) | |
parent | 52109040514ba5f9f20ef3e93e97571e67277eee (diff) |
Merge branch 'redesign' of http://gitlab.pmf.kg.ac.rs/igrannonica/neuronstellar into redesign
# Conflicts:
# frontend/src/app/_elements/folder/folder.component.ts
Diffstat (limited to 'frontend/src/app')
11 files changed, 383 insertions, 266 deletions
diff --git a/frontend/src/app/_elements/column-table/column-table.component.html b/frontend/src/app/_elements/column-table/column-table.component.html index 53372574..543a0018 100644 --- a/frontend/src/app/_elements/column-table/column-table.component.html +++ b/frontend/src/app/_elements/column-table/column-table.component.html @@ -1,125 +1,126 @@ -<div id="tabs"> - <div class="folder-tab p-1 rounded-top" *ngFor="let tab of tabs; let i = index" [style]="'z-index:' + calcZIndex(i) + ' ;'" [ngClass]="{'selected-tab' : selectedTab.index == i, 'hover-tab' : hoveringOverTab?.index == i}"> - <a class="m-1 stretched-link tab-link" (click)="selectTab(i)" (mouseenter)="hoverOverTab(i)" (mouseleave)="hoverOverTab(-1)"> +<div *ngIf="loaded"> + <div id="tabs"> + <div class="folder-tab p-1 rounded-top" *ngFor="let tab of tabs; let i = index" [style]="'z-index:' + calcZIndex(i) + ' ;'" [ngClass]="{'selected-tab' : selectedTab.index == i, 'hover-tab' : hoveringOverTab?.index == i}"> + <a class="m-1 stretched-link tab-link" (click)="selectTab(i)" (mouseenter)="hoverOverTab(i)" (mouseleave)="hoverOverTab(-1)"> {{tab.name}} </a> - </div> - <!-- + </div> + <!-- <button mat-button class="p-1 folder-tab-end rounded-top"> Kolone <mat-icon>keyboard_double_arrow_down</mat-icon> </button> --> -</div> -<div id="folder-table" *ngIf="dataset && experiment"> - <!--<div [ngSwitch]="tabToDisplay">--> - <div id="divTable"> + </div> + <div id="folder-table" *ngIf="dataset && experiment"> + <!--<div [ngSwitch]="tabToDisplay">--> + <div id="divTable"> - <div [ngClass]="{'hidden': tabToDisplay != Table.Data}"> - <table class="table text-offwhite fixed bg-blur"> - <colgroup> - <col class="col-first"> - <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> - </colgroup> - <thead> - <tr> - <th>#</th> - <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> - <div class="cell-align"> - #{{i + 1}} {{colInfo.columnName}} - <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> - </div> - </th> - </tr> - </thead> - <tbody> - <tr *ngFor="let row of tableData; let i = index"> - <th>#{{i}}</th> - <td *ngFor="let col of row; let j = index" [ngClass]="{'text-disabled' : !columnsChecked[j]}"> - <div class="text-overflow"> - {{col}} - </div> - </td> - </tr> - </tbody> - </table> - </div> + <div [ngClass]="{'hidden': tabToDisplay != Table.Data}"> + <table class="table text-offwhite fixed bg-blur"> + <colgroup> + <col class="col-first"> + <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> + </colgroup> + <thead> + <tr> + <th>#</th> + <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> + <div class="cell-align"> + #{{i + 1}} {{colInfo.columnName}} + <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> + </div> + </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let row of tableData; let i = index"> + <th>#{{i}}</th> + <td *ngFor="let col of row; let j = index" [ngClass]="{'text-disabled' : !columnsChecked[j]}"> + <div class="text-overflow"> + {{col}} + </div> + </td> + </tr> + </tbody> + </table> + </div> - <div [ngClass]="{'hidden': tabToDisplay != Table.CorrelationMatrix}"> - <table class="table text-offwhite fixed bg-blur"> - <colgroup> - <col class="col-first"> - <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> - </colgroup> - <thead> - <tr> - <th>Kolona</th> - <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> - <div class="cell-align"> - #{{i + 1}} {{colInfo.columnName}} - <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> - </div> - </th> - </tr> - </thead> - <tbody> - <tr *ngFor="let colInfo of dataset.columnInfo; let i = index"> - <th [ngClass]="{'header-disabled col-disabled' : !columnsChecked[i]}"> - <div class="text-left"> - {{colInfo.columnName}} - </div> - </th> - <td *ngFor="let colInfo of dataset.columnInfo; let j = index" [ngClass]="{'text-disabled col-disabled' : !columnsChecked[j] || !columnsChecked[i]}"> - <div class="text-overflow"> - 0.1 - </div> - </td> - </tr> - </tbody> - </table> - </div> + <div [ngClass]="{'hidden': tabToDisplay != Table.CorrelationMatrix}"> + <table class="table text-offwhite fixed bg-blur"> + <colgroup> + <col class="col-first"> + <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> + </colgroup> + <thead> + <tr> + <th>Kolona</th> + <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> + <div class="cell-align"> + #{{i + 1}} {{colInfo.columnName}} + <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> + </div> + </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let colInfo of dataset.columnInfo; let i = index"> + <th [ngClass]="{'header-disabled col-disabled' : !columnsChecked[i]}"> + <div class="text-left"> + {{colInfo.columnName}} + </div> + </th> + <td *ngFor="let colInfo of dataset.columnInfo; let j = index" [ngClass]="{'text-disabled col-disabled' : !columnsChecked[j] || !columnsChecked[i]}"> + <div class="text-overflow"> + 0.1 + </div> + </td> + </tr> + </tbody> + </table> + </div> - <div [ngClass]="{'hidden': tabToDisplay != Table.Columns}"> - <table class="table text-offwhite fixed bg-blur"> - <colgroup> - <col class="col-first"> - <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> - </colgroup> - <thead> - <tr> - <th>Naziv</th> - <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> - <div class="cell-align"> - #{{i + 1}} {{colInfo.columnName}} - <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> - </div> - </th> - </tr> - </thead> - <tbody> - <tr> - <th>Tip</th> - <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> - <p class="verticalAlign text-left" style="font-size:13px;" *ngIf="!colInfo.isNumber">Kategorijski</p> - <mat-form-field *ngIf="colInfo.isNumber"> - <mat-select matNativeControl [(value)]="colInfo.columnType" [disabled]="!columnsChecked[i]" (selectionChange)="columnTableChangeDetected()"> - <mat-option [value]="ColumnType.categorical">Kategorijski</mat-option> - <mat-option [value]="ColumnType.numerical">Numerički</mat-option> - </mat-select> - </mat-form-field> - </td> - </tr> - <tr class="graphics-row"> - <th class="no-pad">Grafik</th> - <td class="no-pad" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'graphic-class' : !columnsChecked[i]}"> - <app-box-plot *ngIf="colInfo.columnType == ColumnType.numerical" [width]="150" [height]="150"></app-box-plot> - <app-pie-chart *ngIf="colInfo.columnType == ColumnType.categorical" [width]="150" [height]="150"></app-pie-chart> - </td> - </tr> - <tr> - <th class="border-bottom">Statistika</th> - <td *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'text-disabled' : !columnsChecked[i]}" class="text-left"> - <span *ngIf="colInfo.columnType == ColumnType.numerical"> + <div [ngClass]="{'hidden': tabToDisplay != Table.Columns}"> + <table class="table text-offwhite fixed bg-blur"> + <colgroup> + <col class="col-first"> + <col *ngFor="let column of dataset.columnInfo; let i = index" [ngClass]="{'col-disabled' : !experiment.inputColumns.includes(column.columnName)}"> + </colgroup> + <thead> + <tr> + <th>Naziv</th> + <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'header-disabled' : !columnsChecked[i]}"> + <div class="cell-align"> + #{{i + 1}} {{colInfo.columnName}} + <mat-checkbox color="primary" [(ngModel)]="columnsChecked[i]" (change)="changeInputColumns($event, colInfo.columnName)"></mat-checkbox> + </div> + </th> + </tr> + </thead> + <tbody> + <tr> + <th>Tip</th> + <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> + <p class="verticalAlign text-left" style="font-size:13px;" *ngIf="!colInfo.isNumber">Kategorijski</p> + <mat-form-field *ngIf="colInfo.isNumber"> + <mat-select matNativeControl [(value)]="colInfo.columnType" [disabled]="!columnsChecked[i]" (selectionChange)="columnTypeChanged(colInfo.columnName);"> + <mat-option [value]="ColumnType.categorical">Kategorijski</mat-option> + <mat-option [value]="ColumnType.numerical">Numerički</mat-option> + </mat-select> + </mat-form-field> + </td> + </tr> + <tr class="graphics-row"> + <th class="no-pad">Grafik</th> + <td class="no-pad" *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'graphic-class' : !columnsChecked[i]}"> + <app-box-plot *ngIf="colInfo.columnType == ColumnType.numerical" [width]="150" [height]="150"></app-box-plot> + <app-pie-chart *ngIf="colInfo.columnType == ColumnType.categorical" [width]="150" [height]="150"></app-pie-chart> + </td> + </tr> + <tr> + <th class="border-bottom">Statistika</th> + <td *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'text-disabled' : !columnsChecked[i]}" class="text-left"> + <span *ngIf="colInfo.columnType == ColumnType.numerical"> Mean: {{colInfo.mean}}<br> Median: {{colInfo.median}}<br> Min: {{colInfo.min}}<br> @@ -127,104 +128,104 @@ Q1: {{colInfo.q1}}<br> Q3: {{colInfo.q3}}<br> </span> - <div class="text-overflow" *ngIf="colInfo.columnType == ColumnType.categorical && colInfo.uniqueValuesPercent"> - <span *ngFor="let uniqueValue of colInfo.uniqueValues | slice:0:6; let i = index"> - ({{colInfo.uniqueValuesPercent[i].toFixed(4)}}%) {{uniqueValue}}<br> + <div class="text-overflow" *ngIf="colInfo.columnType == ColumnType.categorical && colInfo.uniqueValuesPercent"> + <span *ngFor="let uniqueValue of colInfo.uniqueValues | slice:0:6; let i = index"> + ({{(colInfo.uniqueValuesPercent[i] * 100).toFixed(2)}}%) {{uniqueValue}}<br> </span> - </div> - </td> - </tr> - <tr style="padding: 0"> - <th class="brighter cell-align long" (click)="openEncodingDialog()"> - <span class="verticalAlign">Enkodiranje</span> - <span class="material-icons-round verticalAlign rotate">settings</span> - </th> - <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> - <mat-form-field> - <mat-select matNativeControl [(value)]="experiment.encodings[i].encoding" [disabled]="!columnsChecked[i]" (selectionChange)="columnTableChangeDetected()"> - <mat-option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" [value]="option"> - {{ optionName }} - </mat-option> - </mat-select> - </mat-form-field> - </td> - </tr> - <tr> - <th class="brighter cell-align" (click)="openMissingValuesDialog()"> - <div id="missingValuesHeader">Nedostajuće<br>vrednosti<br></div> - <span class="material-icons-round rotate">settings</span> - </th> - <td *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> + </div> + </td> + </tr> + <tr style="padding: 0"> + <th class="brighter cell-align long" (click)="openEncodingDialog()"> + <span class="verticalAlign">Enkodiranje</span> + <span class="material-icons-round verticalAlign rotate">settings</span> + </th> + <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> + <mat-form-field> + <mat-select matNativeControl [(value)]="experiment.encodings[i].encoding" [disabled]="!columnsChecked[i]" (selectionChange)="columnTableChangeDetected()"> + <mat-option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" [value]="option"> + {{ optionName }} + </mat-option> + </mat-select> + </mat-form-field> + </td> + </tr> + <tr> + <th class="brighter cell-align" (click)="openMissingValuesDialog()"> + <div id="missingValuesHeader">Nedostajuće<br>vrednosti<br></div> + <span class="material-icons-round rotate">settings</span> + </th> + <td *ngFor="let colInfo of dataset.columnInfo; let i = index" [ngClass]="{'text-disabled' : !columnsChecked[i]}"> - <div *ngIf="colInfo.numNulls > 0"> - <button class="w-100" mat-raised-button [ngClass]="{ 'menu-disabled' : !columnsChecked[i]}" [matMenuTriggerFor]="menu" id="main_{{colInfo.columnName}}" #nullValMenu> + <div *ngIf="colInfo.numNulls > 0"> + <button class="w-100" mat-raised-button [ngClass]="{ 'menu-disabled' : !columnsChecked[i]}" [matMenuTriggerFor]="menu" id="main_{{colInfo.columnName}}" #nullValMenu> <div class="cell-align"> {{nullValOption[i]}} <mat-icon>arrow_drop_down</mat-icon> </div> </button> - <mat-menu #menu="matMenu"> - <!--<button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteColumns, i)" value={{colInfo.columnName}}>Obriši kolonu</button>--> - <button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteRows, i)" value={{colInfo.columnName}}>Obriši redove ({{colInfo.numNulls}})</button> - <button mat-menu-item [matMenuTriggerFor]="fillWith">Popuni sa</button> - </mat-menu> + <mat-menu #menu="matMenu"> + <!--<button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteColumns, i)" value={{colInfo.columnName}}>Obriši kolonu</button>--> + <button mat-menu-item (click)="MissValsDeleteClicked($event, NullValueOptions.DeleteRows, i)" value={{colInfo.columnName}}>Obriši redove ({{colInfo.numNulls}})</button> + <button mat-menu-item [matMenuTriggerFor]="fillWith">Popuni sa</button> + </mat-menu> - <mat-menu #fillWith="matMenu"> - <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.mean}}>Mean ({{colInfo.mean}})</button> - <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.median}}>Median ({{colInfo.median}})</button> - <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.max}}>Max ({{colInfo.max}})</button> - <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.min}}>Min ({{colInfo.min}})</button> + <mat-menu #fillWith="matMenu"> + <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.mean}}>Mean ({{colInfo.mean}})</button> + <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.median}}>Median ({{colInfo.median}})</button> + <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.max}}>Max ({{colInfo.max}})</button> + <button *ngIf="colInfo.isNumber" mat-menu-item (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{colInfo.min}}>Min ({{colInfo.min}})</button> - <button *ngIf="!colInfo.isNumber" mat-menu-item [matMenuTriggerFor]="uniques">Najčešće vrednosti</button> + <button *ngIf="!colInfo.isNumber" mat-menu-item [matMenuTriggerFor]="uniques">Najčešće vrednosti</button> - <button mat-menu-item [matMenuTriggerFor]="replaceWith">Unesi vrednost...</button> - </mat-menu> + <button mat-menu-item [matMenuTriggerFor]="replaceWith">Unesi vrednost...</button> + </mat-menu> - <mat-menu #uniques="matMenu"> - <button mat-menu-item *ngFor="let uniqueValue of colInfo.uniqueValues" (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{uniqueValue}}>{{uniqueValue}}</button> - </mat-menu> + <mat-menu #uniques="matMenu"> + <button mat-menu-item *ngFor="let uniqueValue of colInfo.uniqueValues" (click)="MissValsReplaceClicked($event, colInfo.columnName, i)" value={{uniqueValue}}>{{uniqueValue}}</button> + </mat-menu> - <mat-menu #replaceWith="matMenu"> - <input type="text" id={{colInfo.columnName}} mat-menu-item placeholder="Unesi vrednost..." [value]> - <button [disabled]="getValue(colInfo.columnName) == ''" mat-menu-item value={{getValue(colInfo.columnName)}} (click)="MissValsReplaceClicked($event, colInfo.columnName, i)">Potvrdi unos</button> - </mat-menu> - </div> - <div *ngIf="colInfo.numNulls == 0" class="text-left"> - Nema nedostajućih vrednosti. - </div> - </td> - </tr> - </tbody> - </table> + <mat-menu #replaceWith="matMenu"> + <input type="text" id={{colInfo.columnName}} mat-menu-item placeholder="Unesi vrednost..." [value]> + <button [disabled]="getValue(colInfo.columnName) == ''" mat-menu-item value={{getValue(colInfo.columnName)}} (click)="MissValsReplaceClicked($event, colInfo.columnName, i)">Potvrdi unos</button> + </mat-menu> + </div> + <div *ngIf="colInfo.numNulls == 0" class="text-left"> + Nema nedostajućih vrednosti. + </div> + </td> + </tr> + </tbody> + </table> + </div> </div> </div> -</div> -<div *ngIf="dataset && experiment" class="container-fluid text-offwhite belowColumn mt-3"> - <div class="ns-row"> - <div class="break-2"></div> + <div *ngIf="dataset && experiment" class="container-fluid text-offwhite belowColumn mt-3"> + <div class="ns-row"> + <div class="break-2"></div> - <div class="ns-col rounded"> - <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100"> - <mat-label>Tip problema</mat-label> - <mat-select [(value)]="experiment.type"> - <mat-option [value]="ProblemType.Regression">Regresioni</mat-option> - <mat-option [value]="ProblemType.BinaryClassification">Binarni-klasifikacioni</mat-option> - <mat-option [value]="ProblemType.MultiClassification">Multi-klasifikacioni</mat-option> - </mat-select> - </mat-form-field> - </div> - <div class="ns-col rounded"> - <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100"> - <mat-label>Izlazna kolona</mat-label> - <mat-select [(value)]="experiment.outputColumn" (selectionChange)="changeOutputColumn()"> - <mat-option *ngFor="let inputColumn of experiment.inputColumns" [value]="inputColumn">{{inputColumn}}</mat-option> - </mat-select> - </mat-form-field> - </div> - <div class="break-1"></div> - <div class="ns-col d-flex align-items-center justify-content-center"> - <button mat-button (click)="ok()" class="bottom-button text-offwhite rounded-bottom"> + <div class="ns-col rounded"> + <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100"> + <mat-label>Izlazna kolona</mat-label> + <mat-select [(value)]="experiment.outputColumn" (selectionChange)="changeOutputColumn(this.experiment.inputColumns[0])"> + <mat-option *ngFor="let inputColumn of experiment.inputColumns" [value]="inputColumn">{{inputColumn}}</mat-option> + </mat-select> + </mat-form-field> + </div> + <div class="ns-col rounded"> + <mat-form-field appearance="fill" class="align-items-center justify-content-center pt-3 w-100"> + <mat-label>Tip problema</mat-label> + <mat-select [(value)]="experiment.type"> + <mat-option [value]="ProblemType.Regression">Regresioni</mat-option> + <mat-option [value]="ProblemType.BinaryClassification">Binarni-klasifikacioni</mat-option> + <mat-option [value]="ProblemType.MultiClassification">Multi-klasifikacioni</mat-option> + </mat-select> + </mat-form-field> + </div> + <div class="break-1"></div> + <div class="ns-col d-flex align-items-center justify-content-center"> + <button mat-button (click)="saveExperiment()" class="bottom-button text-offwhite rounded-bottom"> <div class="f-row" style="justify-content: space-around;"> <div>Potvrdi</div> <div class="icon-double pt-1"> @@ -233,6 +234,7 @@ </div> </div> </button> + </div> </div> </div> </div>
\ No newline at end of file diff --git a/frontend/src/app/_elements/column-table/column-table.component.ts b/frontend/src/app/_elements/column-table/column-table.component.ts index 01e4e564..c3d4f206 100644 --- a/frontend/src/app/_elements/column-table/column-table.component.ts +++ b/frontend/src/app/_elements/column-table/column-table.component.ts @@ -8,6 +8,8 @@ import { MissingvaluesDialogComponent } from 'src/app/_modals/missingvalues-dial import { MatCheckboxChange } from '@angular/material/checkbox'; import { CsvParseService } from 'src/app/_services/csv-parse.service'; import { ProblemType } from 'src/app/_data/Model'; +import { ExperimentsService } from 'src/app/_services/experiments.service'; +import { SaveExperimentDialogComponent } from 'src/app/_modals/save-experiment-dialog/save-experiment-dialog.component'; @Component({ selector: 'app-column-table', @@ -17,7 +19,7 @@ import { ProblemType } from 'src/app/_data/Model'; export class ColumnTableComponent implements AfterViewInit { @Input() dataset?: Dataset; - @Input() experiment?: Experiment; + @Input() experiment!: Experiment; @ViewChildren("nullValMenu") nullValMenus!: ElementRef[]; @Output() okPressed: EventEmitter<string> = new EventEmitter(); @Output() columnTableChanged = new EventEmitter(); @@ -31,37 +33,44 @@ export class ColumnTableComponent implements AfterViewInit { nullValOption: string[] = []; columnsChecked: boolean[] = []; //niz svih kolona + loaded: boolean = false; - constructor(private datasetService: DatasetsService, public csvParseService: CsvParseService, public dialog: MatDialog) { + constructor(private datasetService: DatasetsService, private experimentService: ExperimentsService, public csvParseService: CsvParseService, public dialog: MatDialog) { //ovo mi nece trebati jer primam dataset iz druge komponente } - ngAfterViewInit(): void { - this.datasetService.getMyDatasets().subscribe((datasets) => { - this.dataset = datasets[2]; + loadDataset(dataset: Dataset) { + this.dataset = dataset; - this.setColumnTypeInitial(); - this.experiment = new Experiment(); - this.dataset.columnInfo.forEach(column => { - this.columnsChecked.push(true); - }); - console.log(datasets); - for (let i = 0; i < this.dataset?.columnInfo.length; i++) { - this.experiment?.inputColumns.push(this.dataset.columnInfo[i].columnName); - } - this.experiment.outputColumn = this.experiment.inputColumns[0]; - this.resetColumnEncodings(Encoding.Label); - this.setDeleteRowsForMissingValTreatment(); + this.setColumnTypeInitial(); + + this.dataset.columnInfo.forEach(column => { + this.columnsChecked.push(true); + }); + + for (let i = 0; i < this.dataset?.columnInfo.length; i++) { + this.experiment.inputColumns.push(this.dataset.columnInfo[i].columnName); + } + this.experiment.outputColumn = this.experiment.inputColumns[0]; + this.resetColumnEncodings(Encoding.Label); + this.setDeleteRowsForMissingValTreatment(); - this.nullValOption = [].constructor(this.dataset.columnInfo.length).fill('Obriši redove'); + this.nullValOption = []; + this.dataset.columnInfo.forEach(colInfo => { + this.nullValOption.push(`Obriši redove (${colInfo.numNulls})`); + }); - this.datasetService.getDatasetFilePartial(this.dataset.fileId, 0, 10).subscribe((response: string | undefined) => { - if (response && this.dataset != undefined) { - this.tableData = this.csvParseService.csvToArray(response, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter.toString() == "") ? "," : this.dataset.delimiter); - } - }); + this.datasetService.getDatasetFilePartial(this.dataset.fileId, 0, 10).subscribe((response: string | undefined) => { + if (response && this.dataset != undefined) { + this.tableData = this.csvParseService.csvToArray(response, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter.toString() == "") ? "," : this.dataset.delimiter); + } }); + this.loaded = true; + } + + ngAfterViewInit(): void { + } setColumnTypeInitial() { @@ -90,6 +99,13 @@ export class ColumnTableComponent implements AfterViewInit { this.columnTableChanged.emit(); } + columnTypeChanged(columnName: string) { + if (this.experiment.outputColumn == columnName) + this.changeOutputColumn(columnName); + else + this.columnTableChangeDetected(); + } + changeInputColumns(targetMatCheckbox: MatCheckboxChange, columnName: string) { if (this.experiment != undefined) { @@ -111,7 +127,7 @@ export class ColumnTableComponent implements AfterViewInit { } } - changeOutputColumn() { + changeOutputColumn(columnName: string) { if (this.experiment != undefined && this.dataset != undefined) { let column = this.dataset.columnInfo.filter(x => x.columnName == this.experiment!.outputColumn)[0]; if (column.columnType == ColumnType.numerical) { @@ -187,6 +203,20 @@ export class ColumnTableComponent implements AfterViewInit { this.resetMissingValuesTreatment(selectedMissingValuesOption); }); } + + openSaveExperimentDialog() { + const dialogRef = this.dialog.open(SaveExperimentDialogComponent, { + width: '400px' + }); + dialogRef.afterClosed().subscribe(selectedName => { + this.experiment.name = selectedName; + //napravi odvojene dugmice za save i update -> za update nece da se otvara dijalog za ime + this.experimentService.addExperiment(this.experiment).subscribe((response) => { + console.log(response); + this.okPressed.emit(); + }); + }); + } @@ -239,8 +269,8 @@ export class ColumnTableComponent implements AfterViewInit { return (<HTMLInputElement>document.getElementById(columnName)).value; return '0'; } - ok() { - this.okPressed.emit(); + saveExperiment() { + this.openSaveExperimentDialog(); } diff --git a/frontend/src/app/_elements/folder/folder.component.ts b/frontend/src/app/_elements/folder/folder.component.ts index b7a2e5d4..1e57fdf1 100644 --- a/frontend/src/app/_elements/folder/folder.component.ts +++ b/frontend/src/app/_elements/folder/folder.component.ts @@ -9,6 +9,7 @@ import { FormDatasetComponent } from '../form-dataset/form-dataset.component'; import Experiment from 'src/app/_data/Experiment'; import { ExperimentsService } from 'src/app/_services/experiments.service'; import { PredictorsService } from 'src/app/_services/predictors.service'; +import { SignalRService } from 'src/app/_services/signal-r.service'; import { FormModelComponent } from '../form-model/form-model.component'; @Component({ @@ -43,12 +44,21 @@ export class FolderComponent implements AfterViewInit { searchTerm: string = ''; - constructor(private datasetsService: DatasetsService, private experimentsService: ExperimentsService, private modelsService: ModelsService, private predictorsService: PredictorsService) { + constructor(private datasetsService: DatasetsService, private experimentsService: ExperimentsService, private modelsService: ModelsService, private predictorsService: PredictorsService, private signalRService: SignalRService) { this.tabsToShow.forEach(tab => this.folders[tab] = []); } ngAfterViewInit(): void { - this.refreshFiles(); + this.refreshFiles(null); + + if (this.signalRService.hubConnection) { + this.signalRService.hubConnection.on("NotifyDataset", (dName: string, dId: string) => { + this.refreshFiles(dId); + + }); + } else { + console.warn("Dataset-Load: No connection!"); + } } displayFile() { @@ -79,7 +89,6 @@ export class FolderComponent implements AfterViewInit { this.fileToDisplay = this.newFile; this.newFileSelected = true; this.listView = false; - this.selectedFileChanged.emit(this.newFile); this.displayFile(); } @@ -107,13 +116,16 @@ export class FolderComponent implements AfterViewInit { _initialized: boolean = false; - refreshFiles() { + refreshFiles(selectedDatasetId: string | null) { this.tabsToShow.forEach(tab => { this.folders[tab] = []; }) this.datasetsService.getMyDatasets().subscribe((datasets) => { this.folders[TabType.MyDatasets] = datasets; + if (selectedDatasetId) { + this.selectFile(datasets.filter(x => x._id == selectedDatasetId)[0]); + } }); this.experimentsService.getMyExperiments().subscribe((experiments) => { 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 0410fa65..c0318012 100644 --- a/frontend/src/app/_elements/form-model/form-model.component.html +++ b/frontend/src/app/_elements/form-model/form-model.component.html @@ -78,7 +78,7 @@ <mat-form-field appearance="fill" class="mat-fix"> <mat-label>Broj uzoraka po iteraciji</mat-label> - <mat-select matNativeControl required [(value)]="newModel.batchSize"> + <mat-select matNativeControl [(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> @@ -159,6 +159,8 @@ </mat-form-field> </div> + + <div class="ns-col"> <mat-form-field appearance="fill" class="mat-fix"> <mat-label>Stopa regularizacije svih slojeva</mat-label> @@ -169,56 +171,56 @@ </mat-select> </mat-form-field> </div> - </div> - <!-- LAYERI --> + <!-- LAYERI --> - <div id="layers"> - <div class="layer" *ngFor="let item of newModel.layers; let i=index"> + <div id="layers"> + <div class="layer" *ngFor="let item of newModel.layers; let i=index"> - <mat-form-field appearance="fill" class="mat-fix"> - <mat-label>Aktivacija</mat-label> - <button matPrefix class="btn-clear center-center text-offwhite"> + <mat-form-field appearance="fill" class="mat-fix"> + <mat-label>Aktivacija</mat-label> + <button matPrefix class="btn-clear center-center text-offwhite"> <div> #{{i+1}} </div> </button> - <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> + <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 tm"> - <div class="col-6" style="font-size: 13px;">Broj čvorova</div> - <button class="btn-clear btn-icon bubble" (click)="addNeuron(i)"> + <div class="d-flex flex-row align-items-center justify-content-center tm"> + <div class="col-6" style="font-size: 13px;">Broj čvorova</div> + <button class="btn-clear btn-icon bubble" (click)="addNeuron(i)"> <mat-icon>add</mat-icon> </button> - <div class="col-2 text-center">{{newModel.layers[i].neurons}}</div> - <button class="btn-clear btn-icon bubble" (click)="removeNeuron(i)"> + <div class="col-2 text-center">{{newModel.layers[i].neurons}}</div> + <button class="btn-clear btn-icon bubble" (click)="removeNeuron(i)"> <mat-icon>remove</mat-icon> </button> - </div> + </div> - <mat-form-field appearance="fill" class="mat-fix"> - <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" class="mat-fix"> + <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" class="mat-fix"> - <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> + <mat-form-field appearance="fill" class="mat-fix"> + <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> </div>
\ No newline at end of file diff --git a/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.css b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.css diff --git a/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.html b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.html new file mode 100644 index 00000000..a0b5d771 --- /dev/null +++ b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.html @@ -0,0 +1,12 @@ +<h1 mat-dialog-title>Čuvanje eksperimenta</h1> +<div mat-dialog-content> + <p>Unesite naziv eksperimenta:</p> + <mat-form-field> + <input type="text" matInput [(ngModel)]="selectedName"> + </mat-form-field> + <p>Da li ste sigurni u izbor?</p> +</div> +<div mat-dialog-actions> + <button mat-button [mat-dialog-close]="selectedName" cdkFocusInitial>Da</button> + <button mat-button (click)="onNoClick()">Odustani</button> +</div>
\ No newline at end of file diff --git a/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.spec.ts b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.spec.ts new file mode 100644 index 00000000..5fd6cb71 --- /dev/null +++ b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SaveExperimentDialogComponent } from './save-experiment-dialog.component'; + +describe('SaveExperimentDialogComponent', () => { + let component: SaveExperimentDialogComponent; + let fixture: ComponentFixture<SaveExperimentDialogComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SaveExperimentDialogComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SaveExperimentDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts new file mode 100644 index 00000000..ca01f57e --- /dev/null +++ b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'app-save-experiment-dialog', + templateUrl: './save-experiment-dialog.component.html', + styleUrls: ['./save-experiment-dialog.component.css'] +}) +export class SaveExperimentDialogComponent implements OnInit { + + selectedName: string = ''; + + constructor(public dialogRef: MatDialogRef<SaveExperimentDialogComponent>) { } + + ngOnInit(): void { + } + + onNoClick() { + this.dialogRef.close(); + } +} diff --git a/frontend/src/app/_pages/experiment/experiment.component.html b/frontend/src/app/_pages/experiment/experiment.component.html index 74c59fdf..baae864e 100644 --- a/frontend/src/app/_pages/experiment/experiment.component.html +++ b/frontend/src/app/_pages/experiment/experiment.component.html @@ -27,12 +27,12 @@ <div #stepsContainer class="steps-container"> <div #steps id="step_1" class="step-content"> <div class="step-content-inside"> - <app-folder #folderDataset [type]="FolderType.Dataset" [forExperiment]="experiment" [startingTab]="TabType.NewFile" [tabsToShow]="[TabType.MyDatasets, TabType.PublicDatasets]" (okPressed)="goToPage(1)"></app-folder> + <app-folder #folderDataset [type]="FolderType.Dataset" [forExperiment]="experiment" [startingTab]="TabType.NewFile" [tabsToShow]="[TabType.MyDatasets, TabType.PublicDatasets]" (okPressed)="goToPage(1)" (selectedFileChanged)="setDataset($event)"></app-folder> </div> </div> <div #steps id="step_2" class="step-content"> <div class="step-content-inside"> - <app-column-table (okPressed)="goToPage(2)" (columnTableChanged)="columnTableChangedEvent()" [experiment]="experiment"></app-column-table> + <app-column-table (okPressed)="goToPage(2)" (columnTableChanged)="columnTableChangedEvent()" [experiment]="experiment" [dataset]="dataset"></app-column-table> </div> </div> <div #steps id="step_3" class="step-content"> diff --git a/frontend/src/app/_pages/experiment/experiment.component.ts b/frontend/src/app/_pages/experiment/experiment.component.ts index a767767d..28552664 100644 --- a/frontend/src/app/_pages/experiment/experiment.component.ts +++ b/frontend/src/app/_pages/experiment/experiment.component.ts @@ -2,12 +2,14 @@ import { AfterViewInit, Component, ElementRef, ViewChild, ViewChildren, Input } 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'; +import { FolderFile, FolderType } from 'src/app/_data/FolderFile'; import { FolderComponent, TabType } from 'src/app/_elements/folder/folder.component'; import Experiment from 'src/app/_data/Experiment'; import { ExperimentsService } from 'src/app/_services/experiments.service'; import { ModelsService } from 'src/app/_services/models.service'; import Model from 'src/app/_data/Model'; +import Dataset from 'src/app/_data/Dataset'; +import { ColumnTableComponent } from 'src/app/_elements/column-table/column-table.component'; @Component({ selector: 'app-experiment', @@ -21,9 +23,12 @@ export class ExperimentComponent implements AfterViewInit { @ViewChildren('steps') steps!: ElementRef[]; event: number = 0; - @Input() experiment: Experiment; + experiment: Experiment; + dataset?: Dataset; @ViewChild("folderDataset") folderDataset!: FolderComponent; @ViewChild("folderModel") folderModel!: FolderComponent; + @ViewChild(ColumnTableComponent) columnTable!: ColumnTableComponent; + constructor(private experimentsService: ExperimentsService, private modelsService: ModelsService) { this.experiment = new Experiment("exp1"); @@ -118,4 +123,11 @@ export class ExperimentComponent implements AfterViewInit { console.log("promenio se column-table"); } + setDataset(dataset: FolderFile) { + const d = <Dataset>dataset; + this.experiment.datasetId = d._id; + this.dataset = d; + + this.columnTable.loadDataset(this.dataset); + } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 5a763152..d44bf6ad 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -21,6 +21,7 @@ import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.compon import { YesNoDialogComponent } from './_modals/yes-no-dialog/yes-no-dialog.component'; import { EncodingDialogComponent } from './_modals/encoding-dialog/encoding-dialog.component'; import { MissingvaluesDialogComponent } from './_modals/missingvalues-dialog/missingvalues-dialog.component'; +import { SaveExperimentDialogComponent } from './_modals/save-experiment-dialog/save-experiment-dialog.component'; // Pages import { HomeComponent } from './_pages/home/home.component'; import { ProfileComponent } from './_pages/profile/profile.component'; @@ -89,8 +90,8 @@ export function initializeApp(appConfig: Configuration) { DoughnutChartComponent, HeatmapComponent, MetricViewComponent, - LineChartComponent - + LineChartComponent, + SaveExperimentDialogComponent ], imports: [ BrowserModule, |