aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app
diff options
context:
space:
mode:
authorDanijel Anđelković <adanijel99@gmail.com>2022-05-03 22:44:25 +0200
committerDanijel Anđelković <adanijel99@gmail.com>2022-05-03 22:44:25 +0200
commite09ca08e9a09f4073d15a5341a746d5356da353c (patch)
tree53d2c0aa3b4d9564f4cfaebd348af917c4e4374b /frontend/src/app
parent8462d0080036650a9e79a379a06ae395ccacf0c8 (diff)
parent52109040514ba5f9f20ef3e93e97571e67277eee (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')
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.html390
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.ts82
-rw-r--r--frontend/src/app/_elements/folder/folder.component.ts20
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.html74
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.css0
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.html12
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.spec.ts25
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts21
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.html4
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.ts16
-rw-r--r--frontend/src/app/app.module.ts5
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}}&nbsp;&nbsp;{{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}}&nbsp;&nbsp;{{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}}&nbsp;&nbsp;{{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}}&nbsp;&nbsp;{{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}}&nbsp;&nbsp;{{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}}&nbsp;&nbsp;{{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>&nbsp;
- <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>&nbsp;
+ <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,