aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app/_elements/column-table
diff options
context:
space:
mode:
authorOgnjen Cirkovic <ciraboxkg@gmail.com>2022-05-04 20:29:40 +0200
committerOgnjen Cirkovic <ciraboxkg@gmail.com>2022-05-04 20:29:40 +0200
commit2c852c832bf310feeb6045380a533bb4f832ccfd (patch)
tree6fa81c0c45a4e0e2550e10371050c07b32a74dd0 /frontend/src/app/_elements/column-table
parent45c519d53fee1124c2882c7b353cd930fd311f9e (diff)
parent3ac7a37690765d6c116463dc8a6ef08b18afea50 (diff)
Mergovana grana sa granom redesign. Sredjeni konflikti.
Diffstat (limited to 'frontend/src/app/_elements/column-table')
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.css63
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.html437
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.ts135
3 files changed, 376 insertions, 259 deletions
diff --git a/frontend/src/app/_elements/column-table/column-table.component.css b/frontend/src/app/_elements/column-table/column-table.component.css
index 108efb32..0477b7be 100644
--- a/frontend/src/app/_elements/column-table/column-table.component.css
+++ b/frontend/src/app/_elements/column-table/column-table.component.css
@@ -3,7 +3,6 @@ table.fixed {
display: block;
overflow-x: auto;
white-space: nowrap;
- border: 1px solid var(--ns-primary-50);
font-size: 12px;
border-radius: 4px;
}
@@ -18,7 +17,6 @@ table.fixed td {
max-width: 200px;
min-width: 200px;
vertical-align: middle;
- background-color: var(--ns-bg-dark-100);
margin: 4px;
}
@@ -27,13 +25,12 @@ table.fixed th {
max-width: 120px;
min-width: 120px;
vertical-align: middle;
- background-color: var(--ns-bg-dark-100);
+ background-color: var(--ns-primary-50);
font-size: 14px;
}
table.fixed th:first-child {
text-align: center;
- background-color: var(--ns-primary-25);
}
.columnNames {
@@ -58,8 +55,8 @@ mat-slider {
}
#missingValuesHeader {
- font-size: 12px;
- line-height: 110% !important;
+ font-size: 13px;
+ line-height: 140% !important;
}
.verticalAlign {
@@ -90,7 +87,7 @@ table ::ng-deep .mat-form-field-wrapper {
}
.no-pad {
- padding: 1px;
+ padding: 2px;
margin: 0;
}
@@ -107,7 +104,7 @@ table ::ng-deep .mat-form-field-wrapper {
}
.graphic-class {
- background-color: white !important;
+ opacity: 0.5;
}
@@ -192,8 +189,9 @@ table ::ng-deep .mat-form-field-wrapper {
}
.hidden {
- visibility: hidden;
- height: 1px;
+ /*visibility: hidden;
+ height: 1px;*/
+ display: none;
}
.bottom-button {
@@ -220,4 +218,49 @@ table ::ng-deep .mat-form-field-wrapper {
.long {
height: 3rem;
+}
+
+.col-disabled {
+ background-color: rgb(0, 45, 69);
+}
+
+.text-disabled {
+ color: gray;
+}
+
+.header-disabled {
+ color: gray;
+}
+
+.menu-disabled {
+ pointer-events: none;
+ opacity: .5;
+}
+
+col:not(.col-disabled) {
+ background-color: var(--ns-bg-dark-100);
+}
+
+.col-first {
+ background-color: rgb(1, 56, 86) !important;
+}
+
+
+/* mat-icon rotate */
+
+.rotate {
+ animation: rotation 3s infinite linear;
+}
+
+.rotate:hover {
+ cursor: pointer;
+}
+
+@keyframes rotation {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(359deg);
+ }
} \ No newline at end of file
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 53cb3551..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,235 +1,231 @@
-<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>
- <!--meni ovde-->
</button>
-</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">
- <thead>
- <tr>
- <th>#</th>
- <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
- <div class="cell-align">
- #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
- <mat-checkbox color="primary" checked (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">
- <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">
- <thead>
- <tr>
- <th>Naziv</th>
- <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
- #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
- </th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let colInfo of dataset.columnInfo; let i = index">
- <th>
- <div class="text-left">
- {{colInfo.columnName}}
- </div>
- </th>
- <td *ngFor="let colInfo of dataset.columnInfo; let j = index">
- <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">
- <thead>
- <tr>
- <th>Naziv</th>
- <th class="columnNames" *ngFor="let colInfo of dataset.columnInfo; let i = index">
- <div class="cell-align">
- #{{i + 1}}&nbsp;&nbsp;{{colInfo.columnName}}
- <mat-checkbox color="primary" checked (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">
- <mat-form-field>
- <mat-select matNativeControl [(value)]="colInfo.isNumber">
- <mat-option [value]="false">Kategorijski</mat-option>
- <mat-option [value]="true">Numerički</mat-option>
- </mat-select>
- </mat-form-field>
- </td>
- </tr>
- <tr class="graphics-row">
- <th class="no-pad border-bottom">Grafik</th>
- <td class="graphic-class no-pad" *ngFor="let colInfo of dataset.columnInfo; let i = index">
- <app-box-plot *ngIf="colInfo.isNumber" [width]="150" [height]="150"></app-box-plot>
- <app-pie-chart *ngIf="!colInfo.isNumber" [width]="150" [height]="150"></app-pie-chart>
- </td>
- </tr>
- <tr>
- <th class="brighter">Statistika</th>
- <td *ngFor="let colInfo of dataset.columnInfo; let i = index">
- <span *ngIf="colInfo.isNumber">
- Mean: {{colInfo.mean}}<br>
- Median: {{colInfo.median}}<br>
- Min: {{colInfo.min}}<br>
- Max: {{colInfo.max}}<br>
- <!-- TODO na ML-u: Q1 i Q3 u statistici
- Q1: {{colInfo.q1}}<br>
- Q3: {{colInfo.q3}}<br>
- -->
- </span>
- <div class="text-overflow" *ngIf="!colInfo.isNumber">
- <span *ngFor="let uniqueValue of colInfo.uniqueValues | slice:0:6; let i = index">
- {{uniqueValue}}<br><!-- TODO na ML-u: broj ponavljanja unique values-a u zagradi nek pise -->
- </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">settings</span>
- </th>
- <td *ngFor="let colInfo of dataset.columnInfo; let i = index" class="pad-fix">
- <mat-form-field>
- <mat-select matNativeControl [(value)]="experiment.encodings[i].encoding">
- <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">Regulisanje<br>nedostajućih<br>vrednosti<br></div>
- <span class="material-icons-round">settings</span>
- </th>
- <td *ngFor="let colInfo of dataset.columnInfo; let i = index">
-
- <button class="w-100" mat-raised-button [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</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>
-
- <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>
-
- <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>
-
- </td>
- </tr>
- <!--<tr class="row-height" *ngFor="let row of tableData; let i = index">
- <th *ngIf="i == 0" [attr.rowspan]="tableData!.length">Vrednosti</th>
-
-
- <td class="text-center" *ngFor="let col of row; let j = index">
- <div class="text-overflow">
- {{col}}
- </div>
- </td>
- </tr>-->
- </tbody>
- </table>
- </div>
+ -->
</div>
-</div>
-
-<div class="container-fluid text-offwhite belowColumn mt-3">
- <div class="ns-row">
- <div class="ns-col slider rounded" style="border:1px solid var(--ns-primary)">
+ <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 class="text-center pt-3 pb-0 mb-0"><b>{{testSetDistribution}}%</b> : <b>{{100-testSetDistribution}}%</b></div>
- <div class="text-center pt-0 mt-0">Trening
- <mat-slider min="10" max="90" step="10" [(ngModel)]="testSetDistribution" (input)="updateTestSet($event)"></mat-slider>
- Test</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>
- <div class="ns-col slider rounded" style="border:1px solid var(--ns-primary);margin-left: 10px;">
- <div class="text-center text-offwhite justify-content-center align-items-center">
- <mat-checkbox class="pt-4" color="accent">Nasumični redosled podataka</mat-checkbox>
+ <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>
+ Max: {{colInfo.max}}<br>
+ 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] * 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 *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 #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 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 #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 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="ToDo1">
- <mat-option value="ToDo1">Regresioni</mat-option>
- <mat-option value="ToDo2">Binarni-Klasifikacioni</mat-option>
- <mat-option value="ToDo3">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>
- <mat-option *ngFor="let item of dataset?.columnInfo" [value]="item.columnName">{{item.columnName}}</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 *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>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">
@@ -238,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 9cabf190..c3d4f206 100644
--- a/frontend/src/app/_elements/column-table/column-table.component.ts
+++ b/frontend/src/app/_elements/column-table/column-table.component.ts
@@ -1,13 +1,15 @@
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChildren } from '@angular/core';
-import Dataset from 'src/app/_data/Dataset';
+import Dataset, { ColumnType } from 'src/app/_data/Dataset';
import Experiment, { ColumnEncoding, Encoding, NullValReplacer, NullValueOptions } from 'src/app/_data/Experiment';
import { DatasetsService } from 'src/app/_services/datasets.service';
import { EncodingDialogComponent } from 'src/app/_modals/encoding-dialog/encoding-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { MissingvaluesDialogComponent } from 'src/app/_modals/missingvalues-dialog/missingvalues-dialog.component';
-import { MatSliderChange } from '@angular/material/slider';
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,43 +19,69 @@ import { CsvParseService } from 'src/app/_services/csv-parse.service';
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();
+
Object = Object;
Encoding = Encoding;
NullValueOptions = NullValueOptions;
+ ColumnType = ColumnType;
+ ProblemType = ProblemType;
tableData?: any[][];
nullValOption: string[] = [];
- testSetDistribution: number = 70;
- constructor(private datasetService: DatasetsService, public csvParseService: CsvParseService, public dialog: MatDialog) {
+ columnsChecked: boolean[] = []; //niz svih kolona
+ loaded: boolean = false;
+
+
+ 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[0];
- this.experiment = new Experiment();
+ loadDataset(dataset: Dataset) {
+ this.dataset = dataset;
- console.log(datasets);
- for (let i = 0; i < this.dataset?.columnInfo.length; i++) {
- this.experiment?.inputColumns.push(this.dataset.columnInfo[i].columnName);
- }
- this.resetColumnEncodings(Encoding.Label);
- this.setDeleteColumnsForMissingValTreatment();
+ 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;
}
- setDeleteColumnsForMissingValTreatment() {
+ ngAfterViewInit(): void {
+
+ }
+
+ setColumnTypeInitial() {
+ if (this.dataset != undefined) {
+ for (let i = 0; i < this.dataset.columnInfo.length; i++) {
+ this.dataset.columnInfo[i].columnType = (this.dataset.columnInfo[i].isNumber) ? ColumnType.numerical : ColumnType.categorical;
+ }
+ }
+ }
+
+ setDeleteRowsForMissingValTreatment() {
if (this.experiment != undefined) {
this.experiment.nullValues = NullValueOptions.DeleteRows;
this.experiment.nullValuesReplacers = [];
@@ -67,8 +95,20 @@ export class ColumnTableComponent implements AfterViewInit {
}
}
+ columnTableChangeDetected() {
+ 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) {
+
if (targetMatCheckbox.checked) {
if (this.experiment.inputColumns.filter(x => x == columnName)[0] == undefined) {
this.experiment.inputColumns.push(columnName);
@@ -80,7 +120,26 @@ export class ColumnTableComponent implements AfterViewInit {
//TODO: da se zatamni kolona koja je unchecked
//this.experiment.encodings = this.experiment.encodings.filter(x => x.columnName != columnName); samo na kraju iz enkodinga skloni necekirane
this.experiment.nullValuesReplacers = this.experiment.nullValuesReplacers.filter(x => x.column != columnName);
+ if (columnName == this.experiment.outputColumn)
+ this.experiment.outputColumn = this.experiment.inputColumns[0];
+ }
+ this.columnTableChangeDetected();
+ }
+ }
+
+ 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) {
+ this.experiment.type = ProblemType.Regression;
}
+ else {
+ if (column.uniqueValues!.length == 2)
+ this.experiment.type = ProblemType.BinaryClassification;
+ else
+ this.experiment.type = ProblemType.MultiClassification;
+ }
+ this.columnTableChangeDetected();
}
}
@@ -91,6 +150,7 @@ export class ColumnTableComponent implements AfterViewInit {
this.experiment.encodings.push(new ColumnEncoding(this.dataset?.columnInfo[i].columnName, encodingType));
//console.log(this.experiment.encodings);
}
+ this.columnTableChangeDetected();
}
}
openEncodingDialog() {
@@ -127,9 +187,11 @@ export class ColumnTableComponent implements AfterViewInit {
option: NullValueOptions.DeleteRows,
value: ""
});
- this.nullValOption[i] = "Obriši redove";
+ let numOfRowsToDelete = (this.dataset.columnInfo.filter(x => x.columnName == this.experiment!.inputColumns[i])[0]).numNulls;
+ this.nullValOption[i] = "Obriši redove (" + numOfRowsToDelete + ")";
}
}
+ this.columnTableChangeDetected();
}
}
openMissingValuesDialog() {
@@ -141,13 +203,25 @@ export class ColumnTableComponent implements AfterViewInit {
this.resetMissingValuesTreatment(selectedMissingValuesOption);
});
}
- updateTestSet(event: MatSliderChange) {
- this.testSetDistribution = event.value!;
+
+ 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();
+ });
+ });
}
+
MissValsDeleteClicked(event: Event, replacementType: NullValueOptions, index: number) {
- if (this.experiment != undefined) {
+ if (this.experiment != undefined && this.dataset != undefined) {
let columnName = (<HTMLInputElement>event.currentTarget).value;
let arrayElement = this.experiment.nullValuesReplacers.filter(x => x.column == columnName)[0];
@@ -163,7 +237,9 @@ export class ColumnTableComponent implements AfterViewInit {
arrayElement.value = "";
}
- this.nullValOption[index] = (replacementType == NullValueOptions.DeleteColumns) ? "Obriši kolonu" : "Obriši redove";
+ let numOfRowsToDelete = (this.dataset.columnInfo.filter(x => x.columnName == this.experiment!.inputColumns[index])[0]).numNulls;
+ this.nullValOption[index] = (replacementType == NullValueOptions.DeleteColumns) ? "Obriši kolonu" : "Obriši redove (" + numOfRowsToDelete + ")";
+ this.columnTableChangeDetected();
}
}
@@ -185,6 +261,7 @@ export class ColumnTableComponent implements AfterViewInit {
}
this.nullValOption[index] = "Popuni sa: " + fillValue;
+ this.columnTableChangeDetected();
}
}
getValue(columnName: string): string {
@@ -192,8 +269,8 @@ export class ColumnTableComponent implements AfterViewInit {
return (<HTMLInputElement>document.getElementById(columnName)).value;
return '0';
}
- ok() {
- this.okPressed.emit();
+ saveExperiment() {
+ this.openSaveExperimentDialog();
}