aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/app')
-rw-r--r--frontend/src/app/_data/Dataset.ts19
-rw-r--r--frontend/src/app/_data/Experiment.ts14
-rw-r--r--frontend/src/app/_data/FolderFile.ts1
-rw-r--r--frontend/src/app/_data/Model.ts22
-rw-r--r--frontend/src/app/_data/Predictor.ts25
-rw-r--r--frontend/src/app/_data/User.ts4
-rw-r--r--frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts124
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.css9
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.html5
-rw-r--r--frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts69
-rw-r--r--frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts41
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css12
-rw-r--r--frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html4
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.html12
-rw-r--r--frontend/src/app/_elements/column-table/column-table.component.ts117
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.ts100
-rw-r--r--frontend/src/app/_elements/folder/folder.component.css9
-rw-r--r--frontend/src/app/_elements/folder/folder.component.html41
-rw-r--r--frontend/src/app/_elements/folder/folder.component.ts146
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.css22
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.html26
-rw-r--r--frontend/src/app/_elements/form-dataset/form-dataset.component.ts2
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.css2
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.html36
-rw-r--r--frontend/src/app/_elements/form-model/form-model.component.ts35
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.css25
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.html25
-rw-r--r--frontend/src/app/_elements/metric-view/metric-view.component.ts20
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.html215
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.ts114
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css8
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html29
-rw-r--r--frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts22
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.html4
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.ts13
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css8
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html22
-rw-r--r--frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts8
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.html2
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.ts9
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.css13
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.html24
-rw-r--r--frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts39
-rw-r--r--frontend/src/app/_pages/archive/archive.component.html2
-rw-r--r--frontend/src/app/_pages/archive/archive.component.ts2
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.css14
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.html38
-rw-r--r--frontend/src/app/_pages/experiment/experiment.component.ts5
-rw-r--r--frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts48
-rw-r--r--frontend/src/app/_pages/profile/profile.component.css20
-rw-r--r--frontend/src/app/_pages/profile/profile.component.html19
-rw-r--r--frontend/src/app/_pages/profile/profile.component.ts9
-rw-r--r--frontend/src/app/_pages/settings/settings.component.css0
-rw-r--r--frontend/src/app/_pages/settings/settings.component.html1
-rw-r--r--frontend/src/app/_pages/settings/settings.component.spec.ts25
-rw-r--r--frontend/src/app/_pages/settings/settings.component.ts15
-rw-r--r--frontend/src/app/app.component.html2
-rw-r--r--frontend/src/app/experiment/experiment.component.html255
-rw-r--r--frontend/src/app/experiment/experiment.component.ts222
-rw-r--r--frontend/src/app/training/training.component.html46
60 files changed, 798 insertions, 1422 deletions
diff --git a/frontend/src/app/_data/Dataset.ts b/frontend/src/app/_data/Dataset.ts
index 4ff0a471..a962fe6b 100644
--- a/frontend/src/app/_data/Dataset.ts
+++ b/frontend/src/app/_data/Dataset.ts
@@ -1,7 +1,6 @@
import { FolderFile } from "./FolderFile";
export default class Dataset extends FolderFile {
- _id: string = '';
constructor(
name: string = 'Novi izvor podataka',
public description: string = '',
@@ -29,15 +28,15 @@ export class ColumnInfo {
public columnName: string = '',
public isNumber: boolean = false,
public numNulls: number = 0,
- public uniqueValues?: string[],
- public uniqueValuesCount?: number[],
- public uniqueValuesPercent?: number[],
- public median?: number,
- public mean?: number,
- public min?: number,
- public max?: number,
- public q1?: number,
- public q3?: number,
+ public uniqueValues: string[]=[],
+ public uniqueValuesCount: number[]=[],
+ public uniqueValuesPercent: number[]=[],
+ public median: number=0,
+ public mean: number=0,
+ public min: number=0,
+ public max: number=0,
+ public q1: number=0,
+ public q3: number=0,
) {
/*if (isNumber)
this.columnType = ColumnType.numerical;
diff --git a/frontend/src/app/_data/Experiment.ts b/frontend/src/app/_data/Experiment.ts
index cff77535..c140e100 100644
--- a/frontend/src/app/_data/Experiment.ts
+++ b/frontend/src/app/_data/Experiment.ts
@@ -1,9 +1,9 @@
+import { FolderFile } from "./FolderFile";
import { ProblemType } from "./Model";
-export default class Experiment {
- _id: string = '';
+export default class Experiment extends FolderFile {
uploaderId: string = '';
constructor(
- public name: string = 'Novi eksperiment',
+ name: string = 'Novi eksperiment',
public description: string = '',
public type: ProblemType = ProblemType.Regression,
public datasetId: string = '',
@@ -11,12 +11,14 @@ export default class Experiment {
public outputColumn: string = '',
public nullValues: NullValueOptions = NullValueOptions.DeleteRows,
public nullValuesReplacers: NullValReplacer[] = [],
- public dateCreated: Date = new Date(),
- public lastUpdated: Date = new Date(),
+ dateCreated: Date = new Date(),
+ lastUpdated: Date = new Date(),
public modelIds: string[] = [],
public columnTypes: ColumnType[] = [],
public encodings: ColumnEncoding[] = []//[{columnName: "", columnEncoding: Encoding.Label}]
- ) { }
+ ) {
+ super(name, dateCreated, lastUpdated)
+ }
_columnsSelected: boolean = false;
}
diff --git a/frontend/src/app/_data/FolderFile.ts b/frontend/src/app/_data/FolderFile.ts
index c228f25e..4d1844fd 100644
--- a/frontend/src/app/_data/FolderFile.ts
+++ b/frontend/src/app/_data/FolderFile.ts
@@ -1,4 +1,5 @@
export class FolderFile {
+ public _id: string = "";
constructor(
public name: string,
public dateCreated: Date,
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts
index 526a8290..cc25c91b 100644
--- a/frontend/src/app/_data/Model.ts
+++ b/frontend/src/app/_data/Model.ts
@@ -2,7 +2,6 @@ import { NgIf } from "@angular/common";
import { FolderFile } from "./FolderFile";
export default class Model extends FolderFile {
- _id: string = '';
constructor(
name: string = 'Novi model',
public description: string = '',
@@ -13,7 +12,7 @@ export default class Model extends FolderFile {
// Neural net training settings
public type: ProblemType = ProblemType.Regression,
public optimizer: Optimizer = Optimizer.Adam,
- public lossFunction: LossFunction = LossFunction.MeanSquaredError,
+ public lossFunction: LossFunction = LossFunctionRegression[0],
public inputNeurons: number = 1,
public hiddenLayers: number = 1,
public batchSize: BatchSize = BatchSize.O3,
@@ -132,21 +131,10 @@ export enum LossFunction {
MeanSquaredLogarithmicError = 'mean_squared_logarithmic_error',
HuberLoss = 'Huber'
}
-export enum LossFunctionRegression {
- MeanAbsoluteError = 'mean_absolute_error',
- MeanSquaredError = 'mean_squared_error',
- MeanSquaredLogarithmicError = 'mean_squared_logarithmic_error',
-}
-export enum LossFunctionBinaryClassification {
- BinaryCrossEntropy = 'binary_crossentropy',
- SquaredHingeLoss = 'squared_hinge_loss',
- HingeLoss = 'hinge_loss',
-}
-export enum LossFunctionMultiClassification {
- CategoricalCrossEntropy = 'categorical_crossentropy',
- SparseCategoricalCrossEntropy = 'sparse_categorical_crossentropy',
- KLDivergence = 'kullback_leibler_divergence',
-}
+export const LossFunctionRegression = [LossFunction.MeanAbsoluteError, LossFunction.MeanSquaredError, LossFunction.MeanSquaredLogarithmicError]
+export const LossFunctionBinaryClassification = [LossFunction.BinaryCrossEntropy, LossFunction.SquaredHingeLoss, LossFunction.HingeLoss]
+
+export const LossFunctionMultiClassification = [LossFunction.CategoricalCrossEntropy, LossFunction.SparseCategoricalCrossEntropy, LossFunction.KLDivergence]
export enum Optimizer {
Adam = 'Adam',
diff --git a/frontend/src/app/_data/Predictor.ts b/frontend/src/app/_data/Predictor.ts
index 8aa2b6cb..55d610ed 100644
--- a/frontend/src/app/_data/Predictor.ts
+++ b/frontend/src/app/_data/Predictor.ts
@@ -1,13 +1,28 @@
-export default class Predictor {
- _id: string = '';
+import { FolderFile } from "./FolderFile";
+
+export default class Predictor extends FolderFile {
constructor(
- public name: string = 'Novi prediktor',
+ name: string = 'Novi prediktor',
public description: string = '',
public inputs: string[] = [],
public output: string = '',
public isPublic: boolean = false,
public accessibleByLink: boolean = false,
- public dateCreated: Date = new Date(),
- public uploaderId: string = ''
+ dateCreated: Date = new Date(),
+ lastUpdated: Date = new Date(),
+ public uploaderId: string = '',
+ //public finalMetrics: Metric[] = []
+ public experimentId: string = "",
+ public modelId: string = "",
+ ) {
+ super(name, dateCreated, lastUpdated);
+ }
+}
+
+export class Metric {
+ constructor(
+ public name: string = '',
+ public jsonValue: string = ''
) { }
+
} \ No newline at end of file
diff --git a/frontend/src/app/_data/User.ts b/frontend/src/app/_data/User.ts
index be42ed0a..527bac77 100644
--- a/frontend/src/app/_data/User.ts
+++ b/frontend/src/app/_data/User.ts
@@ -6,6 +6,8 @@ export default class User {
public password: string = '',
public firstName: string = '',
public lastName: string = '',
- public photoId: string = '1' //difoltna profilna slika
+ public photoId: string = '1', //difoltna profilna slika
+ public isPermament:boolean=false,
+ public dateCreated:Date=new Date()
) { }
} \ No newline at end of file
diff --git a/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts
index d6f4b6ec..bf5e3fd6 100644
--- a/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts
+++ b/frontend/src/app/_elements/_charts/box-plot/box-plot.component.ts
@@ -16,16 +16,31 @@ Chart.register(BoxPlotController, BoxAndWiskers, LinearScale, CategoryScale);
})
export class BoxPlotComponent implements AfterViewInit {
- @Input()width?: number;
- @Input()height?: number;
-
+ @Input() width?: number;
+ @Input() height?: number;
+ @Input() mean?: number;
+ @Input() median?: number;
+ @Input() min?: number;
+ @Input() max?: number;
+ @Input() q1?: number;
+ @Input() q3?: number;
+
+ updateChart(min: number, max: number, q1: number, q3: number, median: number) {
+ if (this.myChart) {
+ this.boxplotData.datasets[0].data = [[min, q1, median, q3, max]]
+ this.myChart.update();
+ }
+ };
+
@ViewChild('boxplot') chartRef!: ElementRef;
- constructor() { }
+ constructor() {
+ //this.updateChart();
+ }
boxplotData = {
// define label tree
- labels: ['January'/*, 'February', 'March', 'April', 'May', 'June', 'July'*/],
- datasets: [{
+ //labels: ['January'/*, 'February', 'March', 'April', 'May', 'June', 'July'*/],
+ datasets: [{
label: 'Dataset 1',
backgroundColor: '#0063AB',
borderColor: '#dfd7d7',
@@ -35,68 +50,43 @@ export class BoxPlotComponent implements AfterViewInit {
padding: 10,
itemRadius: 0,
data: [
- randomValues(100, 0, 100),
- /*randomValues(100, 0, 20),
- randomValues(100, 20, 70),
- randomValues(100, 60, 100),
- randomValues(40, 50, 100),
- randomValues(100, 60, 120),
- randomValues(100, 80, 100)*/
- ]}/*, {
- label: 'Dataset 2',
- backgroundColor: 'rgba(0,0,255,0.5)',
- borderColor: 'blue',
- borderWidth: 1,
- outlierColor: '#999999',
- padding: 10,
- itemRadius: 0,
- data: [
- randomValues(100, 60, 100),
- randomValues(100, 0, 100),
- randomValues(100, 0, 20),
- randomValues(100, 20, 70),
- randomValues(40, 60, 120),
- randomValues(100, 20, 100),
- randomValues(100, 80, 100)
- ]
- }*/]
- };
+ randomValues(100, 0, 100),
+ ]
+ }]
+ };
ngAfterViewInit(): void {
- const myChart = new Chart(this.chartRef.nativeElement, {
- type: "boxplot",
- data: this.boxplotData,
- options: {
- /*title: {
- display: true,
- text: 'Predicted world population (millions) in 2050'
- }*/
- plugins:{
- legend: {
- display: false
- },
- },
- scales : {
- x: {
- ticks: {
- color: '#dfd7d7'
- },
- grid: {
- color: "rgba(0, 99, 171, 0.5)"
- }
- },
- y : {
- min: -50,
- max: 200,
- ticks: {
- color: '#dfd7d7'
- },
- grid: {
- color: "rgba(0, 99, 171, 0.5)"
- }
- }
+ this.myChart = new Chart(this.chartRef.nativeElement, {
+ type: "boxplot",
+ data: this.boxplotData,
+ options: {
+ plugins: {
+ legend: {
+ display: false
+ },
+ },
+ scales: {
+ x: {
+ ticks: {
+ color: '#dfd7d7'
+ },
+ grid: {
+ color: "rgba(0, 99, 171, 0.5)"
+ }
+ },
+ y: {
+ min: this.min,
+ max: this.max,
+ ticks: {
+ color: '#dfd7d7'
+ },
+ grid: {
+ color: "rgba(0, 99, 171, 0.5)"
+ }
}
- }
- });
-}
+ }
+ }
+ });
+ }
+ myChart?: Chart;
}
diff --git a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css
index e69de29b..a190693a 100644
--- a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.css
@@ -0,0 +1,9 @@
+canvas{
+
+ width:100% !important;
+ height:90% !important;
+ border: 1px solid var(--ns-primary);
+ background-color: var(--ns-bg-dark-100);
+ border-radius: 5px;
+ margin: 10px;
+ } \ No newline at end of file
diff --git a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html
index 7f18256a..5bb7aae6 100644
--- a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.html
@@ -1,3 +1,4 @@
- <canvas id="myChart" style="width: 100%; height: 530px;">
- </canvas> \ No newline at end of file
+ <canvas id="myChart" >
+ </canvas>
+ \ No newline at end of file
diff --git a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
index 655db9ec..e873618c 100644
--- a/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
+++ b/frontend/src/app/_elements/_charts/line-chart/line-chart.component.ts
@@ -13,22 +13,18 @@ export class LineChartComponent implements AfterViewInit {
dataMAE: number[] = [];
dataMSE: number[] = [];
dataLOSS: number[] = [];
-
+ dataValAcc:number[]=[];
+ dataValMAE:number[]=[];
+ dataValMSE:number[]=[];
+ dataValLoss:number[]=[];
dataEpoch: number[] = [];
constructor() {
- /*let i = 0;
- setInterval(() => {
- this.dataAcc.push(0.5);
- this.dataEpoch.push(i);
- i++;
- this.update();
- }, 200);*/
}
myChart!: Chart;
- update(myEpochs: number[], myAcc: number[], myLoss: number[], myMae: number[], myMse: number[]) {
+ update(myEpochs: number[], myAcc: number[], myLoss: number[], myMae: number[], myMse: number[], myValAcc:number[],myValLoss:number[],myValMae:number[],myValMse:number[]) {
this.dataAcc.length = 0;
this.dataAcc.push(...myAcc);
@@ -42,6 +38,18 @@ export class LineChartComponent implements AfterViewInit {
this.dataLOSS.push(...myLoss);
this.dataMSE.length = 0;
+ this.dataMSE.push(...myValAcc);
+
+ this.dataMSE.length = 0;
+ this.dataMSE.push(...myValLoss);
+
+ this.dataMSE.length = 0;
+ this.dataMSE.push(...myValMae);
+
+ this.dataMSE.length = 0;
+ this.dataMSE.push(...myValMse);
+
+ this.dataMSE.length = 0;
this.dataMSE.push(...myMse);
this.myChart.update();
@@ -54,8 +62,15 @@ export class LineChartComponent implements AfterViewInit {
data: {
labels: this.dataEpoch,
datasets: [{
+
label: 'Accuracy',
data: this.dataAcc,
+ borderWidth: 1,
+
+ },
+ {
+ label: 'VAl_Accuracy',
+ data: this.dataMSE,
borderWidth: 1
},
{
@@ -64,18 +79,47 @@ export class LineChartComponent implements AfterViewInit {
borderWidth: 1
},
{
+ label: 'Val_Loss',
+ data: this.dataMSE,
+ borderWidth: 1
+ },
+ {
label: 'MAE',
data: this.dataMAE,
borderWidth: 1
},
{
+ label: 'Val_MAE',
+ data: this.dataMSE,
+ borderWidth: 1
+ },
+ {
label: 'MSE',
data: this.dataMSE,
borderWidth: 1
+ },
+ {
+ label: 'Val_MSE',
+ data: this.dataMSE,
+ borderWidth: 1
}
]
},
options: {
+ responsive: true,
+ maintainAspectRatio: true,
+
+ plugins: {
+ legend: {
+ labels: {
+ // This more specific font property overrides the global property
+ color:'white',
+ font: {
+ size: 10
+ }
+ }
+ }
+ },
scales: {
x: {
ticks: {
@@ -83,21 +127,24 @@ export class LineChartComponent implements AfterViewInit {
},
grid: {
color: "rgba(0, 99, 171, 0.5)"
- }
+ },
},
y: {
beginAtZero: true,
ticks: {
color: 'white'
+
},
grid: {
color: "rgba(0, 99, 171, 0.5)"
}
}
+ },
+ animation: {
+ duration: 0
}
-
}
}
);
diff --git a/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts
index f141f522..c2bd3262 100644
--- a/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts
+++ b/frontend/src/app/_elements/_charts/pie-chart/pie-chart.component.ts
@@ -10,21 +10,36 @@ export class PieChartComponent implements AfterViewInit {
@Input()width?: number;
@Input()height?: number;
+ @Input()uniqueValues?: string[] = [];
+ @Input()uniqueValuesPercent?: number[] = [];
+
+ updatePieChart(uniqueValues: string[], uniqueValuesPercent: number[]){
+ console.log(this.uniqueValues, this.uniqueValuesPercent);
+ const newPieChartData = {
+ datasets: [{
+ label: "Population (millions)",
+ backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
+ data: [2478,5267,734,784,433],
+ }]
+
+ }
+ };
@ViewChild('piechart') chartRef!: ElementRef;
constructor() { }
+ pieChartData = {
+ datasets: [{
+ label: "Population (millions)",
+ backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
+ data: [2478,5267,734,784,433]
+ }]
+}
+
ngAfterViewInit(): void {
const myChart = new Chart(this.chartRef.nativeElement, {
type: 'pie',
- data: {
- labels: ["Africa", "Asia", "Europe", "Latin America", "North America"],
- datasets: [{
- label: "Population (millions)",
- backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
- data: [2478,5267,734,784,433],
- }]
- },
+ data: this.pieChartData,
options: {
/*title: {
display: true,
@@ -36,11 +51,9 @@ export class PieChartComponent implements AfterViewInit {
},
},
layout: {
- padding: 15}
+ padding: 15
+ }
}
-});
-
- }
+ });}
-
-}
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css
index 005cb692..3e91b926 100644
--- a/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.css
@@ -1,4 +1,8 @@
-#divScatterChart{
-
- display: block;
-} \ No newline at end of file
+canvas{
+ width:95% !important;
+ height:95% !important;
+ border: 1px solid var(--ns-primary);
+ background-color: var(--ns-bg-dark-100);
+ border-radius: 5px;
+ margin: 10px;
+ } \ No newline at end of file
diff --git a/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html
index ef41775a..eedc6ade 100644
--- a/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html
+++ b/frontend/src/app/_elements/_charts/scatterchart/scatterchart.component.html
@@ -1,4 +1,2 @@
-<div id="divScatterChart" style="width: 100%;height: 100%;">
- <canvas id="ScatterCharts" style="width: 100%;height: 280px;"> </canvas>
-</div> \ No newline at end of file
+ <canvas id="ScatterCharts"> </canvas>
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 efc093d2..d07d50b2 100644
--- a/frontend/src/app/_elements/column-table/column-table.component.html
+++ b/frontend/src/app/_elements/column-table/column-table.component.html
@@ -113,8 +113,8 @@
<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="this.experiment.columnTypes[i] == ColumnType.numerical" [width]="150" [height]="150"></app-box-plot>
- <app-pie-chart *ngIf="this.experiment.columnTypes[i] == ColumnType.categorical" [width]="150" [height]="150"></app-pie-chart>
+ <app-box-plot *ngIf="this.experiment.columnTypes[i] == ColumnType.numerical" [width]="150" [height]="150" [mean]="colInfo.mean" [median]="colInfo.median" [min]="colInfo.min" [max]="colInfo.max" [q1]="colInfo.q1" [q3]="colInfo.q3"></app-box-plot>
+ <app-pie-chart *ngIf="this.experiment.columnTypes[i] == ColumnType.categorical" [width]="150" [height]="150" [uniqueValues]="colInfo.uniqueValues" [uniqueValuesPercent]="colInfo.uniqueValuesPercent"></app-pie-chart>
</td>
</tr>
<tr>
@@ -142,7 +142,10 @@
</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-select matNativeControl [(value)]="experiment.encodings[i].encoding" [disabled]="!columnsChecked[i] || experiment.columnTypes[i] == ColumnType.numerical || colInfo.columnName == experiment.outputColumn" (selectionChange)="columnTableChangeDetected()">
+ <mat-option [value]="Encoding.Label" *ngIf="experiment.columnTypes[i] == ColumnType.numerical || colInfo.columnName == experiment.outputColumn" [selected]="experiment.columnTypes[i] == ColumnType.numerical || colInfo.columnName == experiment.outputColumn">
+ Nema enkodiranja
+ </mat-option>
<mat-option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)" [value]="option">
{{ optionName }}
</mat-option>
@@ -208,8 +211,9 @@
<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-select [(value)]="experiment.outputColumn" (selectionChange)="changeProblemType()">
<mat-option *ngFor="let inputColumn of experiment.inputColumns" [value]="inputColumn">{{inputColumn}}</mat-option>
+ <mat-option *ngIf="experiment.inputColumns.length == 0" value="-">-</mat-option>
</mat-select>
</mat-form-field>
</div>
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 c200e674..217eda30 100644
--- a/frontend/src/app/_elements/column-table/column-table.component.ts
+++ b/frontend/src/app/_elements/column-table/column-table.component.ts
@@ -1,4 +1,4 @@
-import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChildren } from '@angular/core';
+import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, ViewChildren } from '@angular/core';
import Dataset from 'src/app/_data/Dataset';
import Experiment, { ColumnEncoding, Encoding, ColumnType, NullValueOptions } from 'src/app/_data/Experiment';
import { DatasetsService } from 'src/app/_services/datasets.service';
@@ -12,6 +12,8 @@ import { ExperimentsService } from 'src/app/_services/experiments.service';
import { SaveExperimentDialogComponent } from 'src/app/_modals/save-experiment-dialog/save-experiment-dialog.component';
import { AlertDialogComponent } from 'src/app/_modals/alert-dialog/alert-dialog.component';
import Shared from 'src/app/Shared';
+import { PieChartComponent } from '../_charts/pie-chart/pie-chart.component';
+import { BoxPlotComponent } from '../_charts/box-plot/box-plot.component';
@Component({
selector: 'app-column-table',
@@ -20,10 +22,13 @@ import Shared from 'src/app/Shared';
})
export class ColumnTableComponent implements AfterViewInit {
+ @ViewChildren(BoxPlotComponent) boxplotComp!: QueryList<BoxPlotComponent>;
+ @ViewChildren(PieChartComponent) piechartComp!: QueryList<PieChartComponent>;
@Input() dataset?: Dataset;
@Input() experiment!: Experiment;
@Output() okPressed: EventEmitter<string> = new EventEmitter();
@Output() columnTableChanged = new EventEmitter();
+ @Output() experimentChanged = new EventEmitter();
Object = Object;
Encoding = Encoding;
@@ -41,9 +46,35 @@ export class ColumnTableComponent implements AfterViewInit {
//ovo mi nece trebati jer primam dataset iz druge komponente
}
+ updateCharts() {
+ //min: number, max: number, q1: number, q3: number, median: number
+ let i = 0;
+ this.boxplotComp.changes.subscribe(() => {
+ const bps = this.boxplotComp.toArray();
+ this.dataset?.columnInfo.forEach(colInfo => {
+ if (this.experiment.columnTypes[i] == ColumnType.numerical) {
+ bps[i].updateChart(colInfo!.min, colInfo.max, colInfo.q1, colInfo.q3, colInfo.median);
+ i++;
+ }
+ });
+ });
+ }
+
+ updatePieChart() {
+ //min: number, max: number, q1: number, q3: number, median: number
+ let i = 0;
+ const pieChart = this.piechartComp.toArray();
+ this.dataset?.columnInfo.forEach(colInfo => {
+ if (this.experiment.columnTypes[i] == ColumnType.categorical) {
+ pieChart[i].updatePieChart(colInfo!.uniqueValues, colInfo.uniqueValuesPercent);
+ i++;
+ }
+ });
+ }
+
loadDataset(dataset: Dataset) {
+ console.log("LOADED DATASET");
this.dataset = dataset;
-
this.setColumnTypeInitial();
this.dataset.columnInfo.forEach(column => {
@@ -62,13 +93,17 @@ export class ColumnTableComponent implements AfterViewInit {
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.tableData = this.csvParseService.csvToArray(response, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "novi red") ? "\t" : this.dataset.delimiter);
}
});
this.loaded = true;
+
+ this.updateCharts();
+ this.updatePieChart();
}
ngAfterViewInit(): void {
+ console.log(this.dataset?.columnInfo);
}
@@ -89,7 +124,10 @@ export class ColumnTableComponent implements AfterViewInit {
}
}
resetOutputColumn() {
- this.experiment.outputColumn = this.experiment.inputColumns[0];
+ if (this.experiment.inputColumns.length > 0)
+ this.experiment.outputColumn = this.experiment.inputColumns[0];
+ else
+ this.experiment.outputColumn = '-';
}
setDeleteRowsForMissingValTreatment() {
@@ -112,7 +150,7 @@ export class ColumnTableComponent implements AfterViewInit {
columnTypeChanged(columnName: string) {
if (this.experiment.outputColumn == columnName)
- this.changeOutputColumn(columnName);
+ this.changeProblemType();
else
this.columnTableChangeDetected();
}
@@ -124,6 +162,8 @@ export class ColumnTableComponent implements AfterViewInit {
if (this.experiment.inputColumns.filter(x => x == columnName)[0] == undefined) {
this.experiment.inputColumns.push(columnName);
}
+ if (this.experiment.inputColumns.length == 1)
+ this.experiment.outputColumn = this.experiment.inputColumns[0];
}
else {
this.experiment.inputColumns = this.experiment.inputColumns.filter(x => x != columnName);
@@ -131,17 +171,21 @@ 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];
+ if (columnName == this.experiment.outputColumn) {
+ if (this.experiment.inputColumns.length > 0)
+ this.experiment.outputColumn = this.experiment.inputColumns[0];
+ else
+ this.experiment.outputColumn = '-';
+ }
}
this.columnTableChangeDetected();
}
}
- changeOutputColumn(columnName: string) {
+ changeProblemType() {
if (this.experiment != undefined && this.dataset != undefined) {
let i = this.dataset.columnInfo.findIndex(x => x.columnName == this.experiment!.outputColumn);
- if (this.experiment.columnTypes[i] == ColumnType.numerical) {
+ if (i == -1 || this.experiment.columnTypes[i] == ColumnType.numerical) {
this.experiment.type = ProblemType.Regression;
}
else {
@@ -157,20 +201,30 @@ export class ColumnTableComponent implements AfterViewInit {
resetColumnEncodings(encodingType: Encoding) {
if (this.experiment != undefined && this.dataset != undefined) {
this.experiment.encodings = [];
- for (let i = 0; i < this.dataset?.columnInfo.length; i++) {
+ for (let i = 0; i < this.dataset.columnInfo.length; i++) {
this.experiment.encodings.push(new ColumnEncoding(this.dataset?.columnInfo[i].columnName, encodingType));
//console.log(this.experiment.encodings);
}
this.columnTableChangeDetected();
}
}
+ resetColumnEncodingsGlobalSetting(encodingType: Encoding) {
+ if (this.experiment != undefined && this.dataset != undefined) {
+ for (let i = 0; i < this.dataset.columnInfo.length; i++) {
+ if (this.experiment.columnTypes[i] == ColumnType.categorical && this.dataset.columnInfo[i].columnName != this.experiment.outputColumn) //promeni
+ this.experiment.encodings[i].encoding = encodingType;
+ }
+ this.columnTableChangeDetected();
+ }
+ }
openEncodingDialog() {
const dialogRef = this.dialog.open(EncodingDialogComponent, {
- width: '300px'
+ width: '400px',
+ data: { experiment: this.experiment, dataset: this.dataset }
});
dialogRef.afterClosed().subscribe(selectedEncoding => {
if (selectedEncoding != undefined)
- this.resetColumnEncodings(selectedEncoding);
+ this.resetColumnEncodingsGlobalSetting(selectedEncoding);
});
}
@@ -217,21 +271,24 @@ export class ColumnTableComponent implements AfterViewInit {
openSaveExperimentDialog() {
const dialogRef = this.dialog.open(SaveExperimentDialogComponent, {
- width: '400px'
+ width: '400px',
+ data: { experiment: this.experiment }
});
- 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) => {
- this.experiment._id = response._id;
- this.okPressed.emit();
- });
+ dialogRef.afterClosed().subscribe(experiment => {
+ if (experiment) {
+ Object.assign(this.experiment, experiment);
+ this.experiment._columnsSelected = true;
+ this.experimentChanged.emit();
+ console.log(this.experiment);
+ }
});
}
openUpdateExperimentDialog() {
this.experimentService.updateExperiment(this.experiment).subscribe((response) => {
- this.experiment = response;
+ Object.assign(this.experiment, response);
+ this.experiment._columnsSelected = true;
+ this.experimentChanged.emit();
Shared.openDialog("Izmena eksperimenta", "Uspešno ste izmenili podatke o eksperimentu.");
});
}
@@ -286,10 +343,20 @@ export class ColumnTableComponent implements AfterViewInit {
return '0';
}
saveExperiment() {
- this.openSaveExperimentDialog();
+ if (this.experiment.inputColumns.length == 0)
+ Shared.openDialog("Upozorenje", "Kako bi eksperiment bio uspešno izveden, neophodno je da izaberete barem dve kolone koje ćete koristiti.");
+ else if (this.experiment.inputColumns.length == 1)
+ Shared.openDialog("Upozorenje", "Kako bi eksperiment bio uspešno izveden, neophodno je da izaberete barem dve kolone koje ćete koristiti (mora postojati bar jedna ulazna i jedna izlazna kolona).");
+ else
+ this.openSaveExperimentDialog();
}
updateExperiment() {
- this.openUpdateExperimentDialog();
+ if (this.experiment.inputColumns.length == 0)
+ Shared.openDialog("Upozorenje", "Kako bi eksperiment bio uspešno izveden, neophodno je da izaberete barem dve kolone koje ćete koristiti.");
+ else if (this.experiment.inputColumns.length == 1)
+ Shared.openDialog("Upozorenje", "Kako bi eksperiment bio uspešno izveden, neophodno je da izaberete barem dve kolone koje ćete koristiti (mora postojati bar jedna ulazna i jedna izlazna kolona).");
+ else
+ this.openUpdateExperimentDialog();
}
@@ -312,10 +379,8 @@ export class ColumnTableComponent implements AfterViewInit {
hoverOverTab(index: number) {
if (index < 0) {
this.hoveringOverTab = null;
- this.tabToDisplay = this.selectedTab.value;
} else {
this.hoveringOverTab = this.tabs[index];
- this.tabToDisplay = this.tabs[index].value;
}
}
@@ -344,3 +409,5 @@ export class Tab {
public value: Table
) { }
}
+
+
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts
deleted file mode 100644
index 73dbf2d2..00000000
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { Component, OnInit, ViewChild, ViewChildren } from '@angular/core';
-import { AddNewDatasetComponent } from '../add-new-dataset/add-new-dataset.component';
-import { ModelsService } from 'src/app/_services/models.service';
-import shared from 'src/app/Shared';
-import Dataset from 'src/app/_data/Dataset';
-import { DatatableComponent, TableData } from 'src/app/_elements/datatable/datatable.component';
-import { DatasetsService } from 'src/app/_services/datasets.service';
-import { CsvParseService } from 'src/app/_services/csv-parse.service';
-import { Output, EventEmitter } from '@angular/core';
-import { SignalRService } from 'src/app/_services/signal-r.service';
-
-@Component({
- selector: 'app-dataset-load',
- templateUrl: './dataset-load.component.html',
- styleUrls: ['./dataset-load.component.css']
-})
-export class DatasetLoadComponent implements OnInit {
-
- @Output() selectedDatasetChangeEvent = new EventEmitter<Dataset>();
-
- @ViewChild(AddNewDatasetComponent) addNewDatasetComponent!: AddNewDatasetComponent;
- @ViewChild(AddNewDatasetComponent) datatable!: DatatableComponent;
-
- datasetLoaded: boolean = false;
- selectedDatasetLoaded: boolean = false;
-
- showMyDatasets: boolean = true;
- myDatasets?: Dataset[];
- existingDatasetSelected: boolean = false;
- selectedDataset?: Dataset;
-
- tableData: TableData = new TableData();
-
- term: string = "";
-
- constructor(private models: ModelsService, private datasets: DatasetsService, private csv: CsvParseService, private signalRService: SignalRService) {
- this.datasets.getMyDatasets().subscribe((datasets) => {
- this.myDatasets = datasets;
- });
- }
-
- viewMyDatasetsForm() {
- this.showMyDatasets = true;
- if (this.selectedDataset != undefined)
- this.resetSelectedDataset();
- //this.resetCbsAndRbs(); //TREBA DA SE DESI
- }
- viewNewDatasetForm() {
- this.showMyDatasets = false;
- if (this.selectedDataset != undefined)
- this.resetSelectedDataset();
- //this.resetCbsAndRbs(); //TREBA DA SE DESI
- }
-
- refreshMyDatasets() {
- this.datasets.getMyDatasets().subscribe((datasets) => {
- this.myDatasets = datasets;
- this.showMyDatasets = true;
- });
- }
-
- selectThisDataset(dataset: Dataset) {
- this.selectedDataset = dataset;
- this.selectedDatasetLoaded = false;
- this.existingDatasetSelected = true;
- this.tableData.hasHeader = this.selectedDataset.hasHeader;
-
- this.tableData.hasInput = true;
- this.tableData.loaded = false;
-
- this.datasets.getDatasetFile(dataset.fileId).subscribe((file: string | undefined) => {
- if (file) {
- this.tableData.loaded = true;
- this.tableData.numRows = this.selectedDataset!.rowCount;
- this.tableData.numCols = this.selectedDataset!.columnInfo.length;
- this.tableData.data = this.csv.csvToArray(file, (dataset.delimiter == "razmak") ? " " : (dataset.delimiter == "") ? "," : dataset.delimiter);
- //this.resetCbsAndRbs(); //TREBA DA SE DESI
- //this.refreshThreeNullValueRadioOptions(); //TREBA DA SE DESI
- this.selectedDatasetLoaded = true;
-
- this.selectedDatasetChangeEvent.emit(this.selectedDataset);
- }
- });
- }
-
- resetSelectedDataset(): boolean {
- this.selectedDatasetChangeEvent.emit(this.selectedDataset);
- return true;
- }
-
- ngOnInit(): void {
- if (this.signalRService.hubConnection) {
- this.signalRService.hubConnection.on("NotifyDataset", _ => {
- this.refreshMyDatasets();
- });
- } else {
- console.warn("Dataset-Load: No connection!");
- }
- }
-}
diff --git a/frontend/src/app/_elements/folder/folder.component.css b/frontend/src/app/_elements/folder/folder.component.css
index 62324d62..ada2dba0 100644
--- a/frontend/src/app/_elements/folder/folder.component.css
+++ b/frontend/src/app/_elements/folder/folder.component.css
@@ -210,4 +210,13 @@
.form-hidden {
display: none;
+}
+
+.predictor {
+ text-decoration: underline;
+}
+
+.highlight-exp {
+ /*font-size: 16px;*/
+ font-weight: 700;
} \ No newline at end of file
diff --git a/frontend/src/app/_elements/folder/folder.component.html b/frontend/src/app/_elements/folder/folder.component.html
index bff066be..8896e7e5 100644
--- a/frontend/src/app/_elements/folder/folder.component.html
+++ b/frontend/src/app/_elements/folder/folder.component.html
@@ -67,17 +67,38 @@
<app-form-dataset [ngClass]="{'form-hidden': type != FolderType.Dataset}" [forExperiment]="forExperiment"></app-form-dataset>
</div>
<div [ngClass]="{'form-hidden' : !listView}" class="list-view">
- <div *ngFor="let file of filteredFiles; let i = index" class="list-item force-link" (click)="selectFile(file)">
- <div class="mx-2">
- {{file.name}}
+ <div *ngFor="let file of filteredFiles; let i = index">
+ <div class="list-item force-link" (click)="selectFile(file)">
+ <div class="mx-2" [ngClass]="{'highlight-exp' : selectedTab == TabType.MyExperiments}">
+ {{file.name}}
+ </div>
+ <div class="mx-2 hover-hide">
+ {{file.lastUpdated | date}}
+ </div>
+ <div class="mx-2 hover-show" *ngIf="selectedTab !== TabType.PublicDatasets && selectedTab !== TabType.PublicModels">
+ <button class="btn-clear file-button" (click)="deleteFile(file, $event)">
+ <mat-icon>delete</mat-icon>
+ </button>
+ </div>
</div>
- <div class="mx-2 hover-hide">
- {{file.lastUpdated | date}}
- </div>
- <div class="mx-2 hover-show" *ngIf="selectedTab !== TabType.PublicDatasets && selectedTab !== TabType.PublicModels">
- <button class="btn-clear file-button" (click)="deleteFile(file, $event)">
- <mat-icon>delete</mat-icon>
- </button>
+ <div *ngIf="type == FolderType.Experiment" class="list-view">
+ <div *ngFor="let predictor of predictorsForExp[file._id];" class="list-item">
+
+ <div class="mx-3">
+ <div class="f-row">
+ <mat-icon>subdirectory_arrow_right</mat-icon>
+ <div class="mx-1">{{predictor.name}}</div>
+ </div>
+ </div>
+ <div class="mx-2 hover-hide">
+ {{predictor.lastUpdated | date}}
+ </div>
+ <div class="mx-2 hover-show">
+ <button class="btn-clear file-button" (click)="deleteFile(predictor, $event)">
+ <mat-icon>delete</mat-icon>
+ </button>
+ </div>
+ </div>
</div>
</div>
diff --git a/frontend/src/app/_elements/folder/folder.component.ts b/frontend/src/app/_elements/folder/folder.component.ts
index fabb524c..665659a8 100644
--- a/frontend/src/app/_elements/folder/folder.component.ts
+++ b/frontend/src/app/_elements/folder/folder.component.ts
@@ -11,6 +11,8 @@ 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';
+import { Router } from '@angular/router';
+import Predictor from 'src/app/_data/Predictor';
@Component({
selector: 'app-folder',
@@ -30,7 +32,7 @@ export class FolderComponent implements AfterViewInit {
@Input() type: FolderType = FolderType.Dataset;
@Input() forExperiment!: Experiment;
@Input() startingTab!: TabType;
-
+ @Input() archive: boolean = false;
newFileSelected: boolean = true;
selectedFileIndex: number = -1;
@@ -44,7 +46,7 @@ export class FolderComponent implements AfterViewInit {
searchTerm: string = '';
- constructor(private datasetsService: DatasetsService, private experimentsService: ExperimentsService, private modelsService: ModelsService, private predictorsService: PredictorsService, private signalRService: SignalRService) {
+ constructor(private datasetsService: DatasetsService, private experimentsService: ExperimentsService, private modelsService: ModelsService, private predictorsService: PredictorsService, private signalRService: SignalRService, private router: Router) {
this.tabsToShow.forEach(tab => this.folders[tab] = []);
}
@@ -91,20 +93,23 @@ export class FolderComponent implements AfterViewInit {
this.newFileSelected = true;
this.listView = false;
this.displayFile();
- if(this.type == FolderType.Dataset)
+ if (this.type == FolderType.Dataset)
this.formDataset.clear();
}
selectFile(file?: FolderFile) {
this.selectedFile = file;
this.fileToDisplay = file;
+ if (this.type == FolderType.Experiment && file) {
+ this.router.navigate(['/experiment'/*, file._id*/])
+ }
this.newFileSelected = false;
this.listView = false;
this.selectedFileChanged.emit(this.selectedFile);
this.selectTab(TabType.File);
this.displayFile();
- if(this.type == FolderType.Dataset)
+ if (this.type == FolderType.Dataset)
this.formDataset.loadExisting();
}
@@ -122,7 +127,7 @@ export class FolderComponent implements AfterViewInit {
_initialized: boolean = false;
- refreshFiles(selectedDatasetId: string | null) {
+ refreshFiles(selectedDatasetId: string | null = null, selectedModelId: string | null = null) {
this.files = []
this.filteredFiles.length = 0;
this.folders[TabType.NewFile] = [];
@@ -131,42 +136,85 @@ export class FolderComponent implements AfterViewInit {
this.folders[tab] = [];
});
- this.datasetsService.getMyDatasets().subscribe((datasets) => {
- this.folders[TabType.MyDatasets] = datasets;
- if (selectedDatasetId) {
- this.selectFile(datasets.filter(x => x._id == selectedDatasetId)[0]);
+ if (this.archive) {
+ this.refreshDatasets(selectedDatasetId);
+ this.refreshModels(selectedModelId);
+ this.refreshExperiments();
+ } else {
+ switch (this.type) {
+ case FolderType.Dataset:
+ this.refreshDatasets(selectedDatasetId);
+ break;
+
+ case FolderType.Model:
+ this.refreshModels(selectedModelId);
+ break;
+
+ case FolderType.Experiment:
+ this.refreshExperiments();
+ break;
+
+ default:
+ console.error("Bad folder type.");
+ break;
}
- });
-
- this.experimentsService.getMyExperiments().subscribe((experiments) => {
- this.folders[TabType.MyExperiments] = experiments;
- });
+ }
- this.datasetsService.getPublicDatasets().subscribe((datasets) => {
- this.folders[TabType.PublicDatasets] = datasets;
- });
+ if (!this._initialized) {
+ this.files = this.folders[this.startingTab];
+ this.filteredFiles = [];
+ this.selectTab(this.startingTab);
+ this._initialized = true;
+ }
+ }
+ refreshModels(selectedModelId: string | null) {
this.modelsService.getMyModels().subscribe((models) => {
this.folders[TabType.MyModels] = models;
+ if (selectedModelId) {
+ this.selectFile(models.filter(x => x._id == selectedModelId)[0]);
+ }
+ this.searchTermsChanged();
});
-
/*this.modelsService.getMyModels().subscribe((models) => {
this.folders[TabType.PublicModels] = models;
+ this.searchTermsChanged();
});*/
this.folders[TabType.PublicModels] = [];
+ }
+ refreshDatasets(selectedDatasetId: string | null) {
+ this.datasetsService.getMyDatasets().subscribe((datasets) => {
+ this.folders[TabType.MyDatasets] = datasets;
+ if (selectedDatasetId) {
+ this.selectFile(datasets.filter(x => x._id == selectedDatasetId)[0]);
+ }
+ this.searchTermsChanged();
+ });
+ this.datasetsService.getPublicDatasets().subscribe((datasets) => {
+ this.folders[TabType.PublicDatasets] = datasets;
+ this.searchTermsChanged();
+ });
+ }
+
+ refreshExperiments() {
this.experimentsService.getMyExperiments().subscribe((experiments) => {
this.folders[TabType.MyExperiments] = experiments;
+ this.predictorsService.getMyPredictors().subscribe((predictors) => {
+ this.predictorsForExp = {};
+ experiments.forEach(exp => {
+ this.predictorsForExp[exp._id] = predictors.filter(pred => pred.experimentId == exp._id);
+ /* TODO IZMENI OVO DA SE SETUJE NA BACKU AUTOMATSKI */
+ this.predictorsForExp[exp._id].forEach(pred => {
+ const model = this.folders[TabType.MyModels].find(model => model._id == pred.modelId);
+ pred.name = model?.name!;
+ pred.lastUpdated = model?.lastUpdated!;
+ })
+ /* ------------------------------------------------ */
+ this.searchTermsChanged();
+ })
+ });
});
-
- if (!this._initialized) {
- this.files = this.folders[this.startingTab];
- this.filteredFiles = [];
- this.selectTab(this.startingTab);
- this._initialized = true;
- }
-
- this.searchTermsChanged();
}
saveNewFile() {
@@ -175,7 +223,7 @@ export class FolderComponent implements AfterViewInit {
this.formDataset!.uploadDataset((dataset: Dataset) => {
this.newFile = undefined;
Shared.openDialog("Obaveštenje", "Uspešno ste dodali novi izvor podataka u kolekciju. Molimo sačekajte par trenutaka da se procesira.");
- this.refreshFiles(null);
+ this.refreshFiles();
},
() => {
Shared.openDialog("Neuspeo pokušaj!", "Izvor podataka sa unetim nazivom već postoji u Vašoj kolekciji. Izmenite naziv ili iskoristite postojeći dataset.");
@@ -185,7 +233,7 @@ export class FolderComponent implements AfterViewInit {
this.modelsService.addModel(this.formModel.newModel).subscribe(model => {
this.newFile = undefined;
Shared.openDialog("Obaveštenje", "Uspešno ste dodali novu konfiguraciju neuronske mreže u kolekciju.");
- this.refreshFiles(null); // todo select model
+ this.refreshFiles(null, model._id); // todo select model
}, (err) => {
Shared.openDialog("Neuspeo pokušaj!", "Konfiguracija neuronske mreže sa unetim nazivom već postoji u Vašoj kolekciji. Izmenite naziv ili iskoristite postojeću konfiguraciju.");
});
@@ -193,19 +241,7 @@ export class FolderComponent implements AfterViewInit {
}
}
-
- /*calcZIndex(i: number) {
- let zIndex = (this.files.length - i - 1)
- if (this.selectedFileIndex == i)
- zIndex = this.files.length + 2;
- if (this.hoveringOverFileIndex == i)
- zIndex = this.files.length + 3;
- return zIndex;
- }
-
- newFileZIndex() {
- return (this.files.length + 1);
- }*/
+ predictorsForExp: { [expId: string]: Predictor[] } = {}
clearSearchTerm() {
this.searchTerm = '';
@@ -232,10 +268,6 @@ export class FolderComponent implements AfterViewInit {
listView: boolean = true;
- toggleListView() {
- this.listView = !this.listView;
- }
-
deleteFile(file: FolderFile, event: Event) {
event.stopPropagation();
//console.log('delete');
@@ -349,16 +381,22 @@ export class FolderComponent implements AfterViewInit {
}
hoverOverTab(tab: TabType) {
- this.listView = this.getListView(tab);
- this.privacy = this.getPrivacy(tab);
+ // this.listView = this.getListView(tab);
+ // this.privacy = this.getPrivacy(tab);
this.hoverTab = tab;
- if (tab == TabType.None) {
- this.listView = this.getListView(this.selectedTab);
- this.files = this.folders[this.selectedTab];
- } else {
- this.files = this.folders[tab];
+ // if (tab == TabType.None) {
+ // this.listView = this.getListView(this.selectedTab);
+ // this.files = this.folders[this.selectedTab];
+ // } else {
+ // this.files = this.folders[tab];
+ // }
+ // this.searchTermsChanged();
+ }
+
+ updateExperiment() {
+ if (this.formModel) {
+ this.formModel.updateGraph();
}
- this.searchTermsChanged();
}
}
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.css b/frontend/src/app/_elements/form-dataset/form-dataset.component.css
index 953daa0c..079711d0 100644
--- a/frontend/src/app/_elements/form-dataset/form-dataset.component.css
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.css
@@ -5,25 +5,27 @@
}
.topBar {
+ display: table;
width: 100%;
- margin: 1rem;
- align-items: flex-start;
+ height: 100px;
+ margin-left: 1.5%;
+ margin-top: 1.5% ;
+}
+.kolona{
+ float: left;
+ margin-left: 20px;
}
-
.topBar label{
font-size: 30px;
}
.topBar mat-form-field{
width: 250px;
+ margin: 0;
}
-.toptop{
- margin-left: 1.5%;
- width: 50%;
-}
-
-.fileButton{
- margin-top: 10px;
+.fileButton button{
+ height: 51px;
+ width: 250px;
}
.file-container {
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.html b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
index 281f9c05..b96276bd 100644
--- a/frontend/src/app/_elements/form-dataset/form-dataset.component.html
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.html
@@ -1,18 +1,16 @@
<div class="folderBox" *ngIf="dataset">
- <div class="row" style="margin-right: 0;">
+
<div class="topBar">
- <div class="row toptop">
- <div class="col-sm mb-3">
+ <div class="kolona mb-3">
<div class="fileButton">
<button type="button" mat-raised-button (click)="fileInput.click()">Dodaj izvor podataka</button>
</div>
</div>
- <div class="col-sm">
+ <div class="kolona">
<div role="group">
- <div class="row">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Naziv</mat-label>
<input type="text" matInput value="{{dataset?.name}}" [(ngModel)]="dataset.name">
@@ -22,30 +20,24 @@
Naziv je <strong>obavezan</strong>
</mat-error>
</mat-form-field>
- </div>
</div>
</div>
- <div class="col-sm">
+ <div class="kolona">
<mat-form-field appearance="fill">
<mat-label>Delimiter</mat-label>
- <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (change)="update()" value=",">
+ <mat-select id="delimiterOptions" [(ngModel)]="dataset.delimiter" (selectionChange)="update()" value=",">
<mat-option *ngFor="let option of delimiterOptions" [value]="option">
{{ option }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
- <div class="col-sm">
-
- </div>
- </div>
- <div class="row" *ngIf="firstInput">
- <label class=" mt-5">{{filename}}</label>
-
- </div>
</div>
- </div>
+
+ <div class="row" *ngIf="firstInput">
+ <label class=" mt-5">{{filename}}</label>
+ </div>
<div class="row" style="margin-right: 0;">
<div class="file-container" [ngClass]="{'dottedClass': !tableData.hasInput}">
diff --git a/frontend/src/app/_elements/form-dataset/form-dataset.component.ts b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
index 1eed2cdc..94ef9905 100644
--- a/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
+++ b/frontend/src/app/_elements/form-dataset/form-dataset.component.ts
@@ -101,7 +101,7 @@ export class FormDatasetComponent {
this.tableData.loaded = true;
this.tableData.numRows = this.dataset.rowCount;
this.tableData.numCols = this.dataset.columnInfo.length;
- this.tableData.data = this.csv.csvToArray(file, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "") ? "," : this.dataset.delimiter);
+ this.tableData.data = this.csv.csvToArray(file, (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "novi red") ? "\t" : this.dataset.delimiter);
}
});
diff --git a/frontend/src/app/_elements/form-model/form-model.component.css b/frontend/src/app/_elements/form-model/form-model.component.css
index 11b6ef5e..95ace1ef 100644
--- a/frontend/src/app/_elements/form-model/form-model.component.css
+++ b/frontend/src/app/_elements/form-model/form-model.component.css
@@ -101,4 +101,4 @@ mat-slider {
padding-bottom: 15px;
font-size: 20px !important;
font-weight: 600;
-} \ No newline at end of file
+}
diff --git a/frontend/src/app/_elements/form-model/form-model.component.html b/frontend/src/app/_elements/form-model/form-model.component.html
index 96a5e1b6..09e44a99 100644
--- a/frontend/src/app/_elements/form-model/form-model.component.html
+++ b/frontend/src/app/_elements/form-model/form-model.component.html
@@ -11,7 +11,12 @@
<div class="ns-col">
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Tip problema</mat-label>
- <mat-select [(ngModel)]="newModel.type">
+ <mat-select [(ngModel)]="newModel.type" (selectionChange)="filterLossFunction()" *ngIf="this.hideProblemType" disabled="true">
+ <mat-option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option">
+ {{ optionName }}
+ </mat-option>
+ </mat-select>
+ <mat-select [(ngModel)]="newModel.type" (selectionChange)="filterLossFunction()" *ngIf="!this.hideProblemType" disabled="false">
<mat-option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option">
{{ optionName }}
</mat-option>
@@ -36,7 +41,7 @@
<mat-form-field appearance="fill" class="mat-fix">
<mat-label>Funkcija troška</mat-label>
<mat-select [(ngModel)]="newModel.lossFunction">
- <mat-option *ngFor="let option of Object.keys(LossFunction); let optionName of Object.values(LossFunction)" [value]="option">
+ <mat-option *ngFor="let option of Object.keys(lossFunction); let optionName of Object.values(lossFunction)" [value]="option">
{{ optionName }}
</mat-option>
</mat-select>
@@ -109,7 +114,7 @@
<div class="col-sm-9">
<!-- {{forExperiment._columnsSelected}} -->
- <app-graph [model]="newModel" *ngIf="forExperiment._columnsSelected" [inputColumns]="forExperiment.inputColumns"></app-graph>
+ <app-graph [model]="newModel" *ngIf="forExperiment._columnsSelected" [inputColumns]="getInputColumns()"></app-graph>
<app-graph [model]="newModel" *ngIf="!forExperiment._columnsSelected" [inputColumns]="['Nisu odabrane ulazne kolone']"></app-graph>
</div>
</div>
@@ -121,14 +126,15 @@
<div class="ns-col" id="layers-control">
<div>Broj Skrivenih Slojeva</div>
- <button class="btn-clear btn-icon bubble" (click)="addLayer()">
- <mat-icon>add</mat-icon>
- </button>
- <div>{{newModel.hiddenLayers}}</div>
<button class="btn-clear btn-icon bubble" (click)="removeLayer()">
- <mat-icon>remove</mat-icon>
- </button>
+ <mat-icon>remove</mat-icon>
+ </button>
+ <div>{{newModel.hiddenLayers}}</div>
+
+ <button class="btn-clear btn-icon bubble" (click)="addLayer()">
+ <mat-icon>add</mat-icon>
+ </button>
</div>
<div class="break-1"></div>
<div class="ns-col">
@@ -196,13 +202,13 @@
<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)">
- <mat-icon>remove</mat-icon>
- </button>
+ <mat-icon>remove</mat-icon>
+ </button>
+ <div class="col-2 text-center">{{newModel.layers[i].neurons}}</div>
+ <button class="btn-clear btn-icon bubble" (click)="addNeuron(i)">
+ <mat-icon>add</mat-icon>
+ </button>
</div>
<mat-form-field appearance="fill" class="mat-fix">
diff --git a/frontend/src/app/_elements/form-model/form-model.component.ts b/frontend/src/app/_elements/form-model/form-model.component.ts
index 71b374b0..e01c2339 100644
--- a/frontend/src/app/_elements/form-model/form-model.component.ts
+++ b/frontend/src/app/_elements/form-model/form-model.component.ts
@@ -15,8 +15,13 @@ export class FormModelComponent implements AfterViewInit {
@ViewChild(GraphComponent) graph!: GraphComponent;
@Input() forExperiment!: Experiment;
@Output() selectedModelChangeEvent = new EventEmitter<Model>();
+ @Input() hideProblemType:boolean;
+ @Input() forProblemType:ProblemType;
testSetDistribution: number = 70;
- constructor() { }
+ constructor() {
+ this.hideProblemType=false;
+ this.forProblemType=ProblemType.BinaryClassification;
+ }
ngAfterViewInit(): void { }
@@ -80,13 +85,6 @@ export class FormModelComponent implements AfterViewInit {
}
}
- /*
- setNeurons()
- {
- for(let i=0;i<this.newModel.hiddenLayers;i++){
- this.newModel.hiddenLayerNeurons[i]=1;
- }
- }*/
numSequence(n: number): Array<number> {
return Array(n);
}
@@ -111,9 +109,7 @@ export class FormModelComponent implements AfterViewInit {
changeAllActivation() {
for (let i = 0; i < this.newModel.layers.length; i++) {
this.newModel.layers[i].activationFunction = this.selectedActivation;
-
}
-
}
changeAllRegularisation() {
for (let i = 0; i < this.newModel.layers.length; i++) {
@@ -131,8 +127,25 @@ export class FormModelComponent implements AfterViewInit {
this.updateGraph();
}
}
-
updateTestSet(event: MatSliderChange) {
this.testSetDistribution = event.value!;
}
+ filterLossFunction() {
+ if(this.newModel.type==ProblemType.Regression){
+ this.lossFunction = LossFunctionRegression;
+ this.newModel.lossFunction=LossFunction.MeanSquaredError;
+ }
+ else if(this.newModel.type==ProblemType.BinaryClassification){
+ this.lossFunction= LossFunctionBinaryClassification;
+ this.newModel.lossFunction=LossFunction.BinaryCrossEntropy;
+ }
+ else if(this.newModel.type==ProblemType.MultiClassification){
+ this.lossFunction = LossFunctionMultiClassification;
+ this.newModel.lossFunction=LossFunction.SparseCategoricalCrossEntropy;
+ }
+
+}
+getInputColumns() {
+ return this.forExperiment.inputColumns.filter(x => x != this.forExperiment.outputColumn);
+}
}
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.css b/frontend/src/app/_elements/metric-view/metric-view.component.css
index f91c1ccc..d27418c3 100644
--- a/frontend/src/app/_elements/metric-view/metric-view.component.css
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.css
@@ -1,10 +1,23 @@
-#container{
+.row{
+ margin: 0 !important;
+ padding: 0 !important;
+}
+.container{
width: 100%;
height: 90%;
border-radius: 5px;
- background-color:var(--ns-primary-25);
- border:1px solid var(--ns-accent);
+ border:1px solid var(--ns-primary);
+ background-color: rgba(0, 65, 101, 0.7);
+ margin-top: 20px;
+ margin: 0 !important;
+ padding: 0 !important;
+ width: 100%;
+ height: 100%;
+}
+app-line-chart{
+ width: 100%;
+ height: 100%;
+ border-radius: 5px;
+ border:1px solid var(--ns-primary);
+ background-color: rgba(0, 65, 101, 0.7);
}
-#line{
- background-color:#dfd7d7f0 ;
-} \ No newline at end of file
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.html b/frontend/src/app/_elements/metric-view/metric-view.component.html
index d72bc92b..2ab0a425 100644
--- a/frontend/src/app/_elements/metric-view/metric-view.component.html
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.html
@@ -1,8 +1,21 @@
-<div id="container" class="d-flex justify-content-center flex-row w-100">
- <div id="line" style="width: 100%;height: 100%;background-color:var(--ns-bg-dark-100);">
- <app-line-chart></app-line-chart>
+ <!--<div class="container" style="margin:auto;">
+ <div class="row">
+ <div class="col-xl">
+ <div class="demo-content"><app-line-chart-acc [dataAcc]="myAcc" [dataEpoch]=""[dataValAcc]=""></app-line-chart-acc></div>
+ </div>
+ <div class="col-xl">
+ <div class="demo-content"><app-line-chart-loss></app-line-chart-loss></div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-xl">
+ <div class="demo-content"><app-line-chart-mae></app-line-chart-mae></div>
</div>
- <div style="background-color: var(--ns-bg-dark-100);width: 50%;height: 50%;">
- <app-scatterchart></app-scatterchart>
+ <div class="col-xl">
+ <div class="demo-content"><app-line-chart-mse></app-line-chart-mse></div>
</div>
-</div> \ No newline at end of file
+</div>
+</div>-->
+<app-line-chart></app-line-chart>
+
+
diff --git a/frontend/src/app/_elements/metric-view/metric-view.component.ts b/frontend/src/app/_elements/metric-view/metric-view.component.ts
index 6fd2f320..fbca2edf 100644
--- a/frontend/src/app/_elements/metric-view/metric-view.component.ts
+++ b/frontend/src/app/_elements/metric-view/metric-view.component.ts
@@ -1,6 +1,5 @@
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { LineChartComponent } from '../_charts/line-chart/line-chart.component';
-
@Component({
selector: 'app-metric-view',
templateUrl: './metric-view.component.html',
@@ -9,6 +8,7 @@ import { LineChartComponent } from '../_charts/line-chart/line-chart.component';
export class MetricViewComponent implements OnInit {
@ViewChild(LineChartComponent) linechartComponent!: LineChartComponent;
+
constructor() { }
ngOnInit(): void {
@@ -21,6 +21,10 @@ export class MetricViewComponent implements OnInit {
const myMae: number[] = [];
const myMse: number[] = [];
const myLoss: number[] = [];
+ const myValLoss: number[] = [];
+ const myValAcc: number[] = [];
+ const myValMAE: number[] = [];
+ const myValMSE: number[] = [];
const myEpochs: number[] = [];
this.history = history;
@@ -41,9 +45,21 @@ export class MetricViewComponent implements OnInit {
else if (key === 'mse') {
myMse.push(parseFloat(value));
}
+ else if (key === 'val_acc') {
+ myValAcc.push(parseFloat(value));
+ }
+ else if (key === 'val_loss') {
+ myValLoss.push(parseFloat(value));
+ }
+ else if (key === 'val_mae') {
+ myValMAE.push(parseFloat(value));
+ }
+ else if (key === 'val_mse') {
+ myValMSE.push(parseFloat(value));
+ }
}
});
- this.linechartComponent.update(myEpochs, myAcc, myLoss, myMae, myMse);
+ this.linechartComponent.update(myEpochs, myAcc, myLoss, myMae, myMse, myValAcc,myValLoss,myValMAE,myValMSE);
}
} \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.html b/frontend/src/app/_elements/model-load/model-load.component.html
deleted file mode 100644
index dcb35c21..00000000
--- a/frontend/src/app/_elements/model-load/model-load.component.html
+++ /dev/null
@@ -1,215 +0,0 @@
-<div>
- <div class="d-flex flex-row justify-content-center align-items-center mt-3 mb-5">
- <button type="button" id="btnMyModel" class="btn" (click)="viewMyModelsForm()"
- [ngClass]="{'btnType1': showMyModels, 'btnType2': !showMyModels}">
- Izaberite model iz kolekcije
- </button>
- <h3 class="mt-3 mx-3">ili</h3>
- <button type="button" id="btnNewModel" class="btn" (click)="viewNewModelForm()"
- [ngClass]="{'btnType1': !showMyModels, 'btnType2': showMyModels}">
- Dodajte novi model
- </button>
- </div>
-
- <div *ngIf="showMyModels" class="px-5 my-3">
- <input *ngIf="showMyModels" type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term">
- </div>
- <div *ngIf="showMyModels" class="px-5">
- <div class="overflow-auto" style="max-height: 500px;">
- <ul class="list-group">
- <li class="list-group-item p-3" *ngFor="let model of myModels|filter:term|filter:(forExperiment ? forExperiment.type : '')"
- [ngClass]="{'selectedModelClass': this.selectedModel == model}">
- <app-item-model name="usersModel" [model]="model" (click)="selectThisModel(model);">
- </app-item-model>
- </li>
- </ul>
- <div class="px-5 mt-5">
- <!--prikaz izabranog modela-->
- </div>
- </div>
- </div>
-
-
- <div *ngIf="!showMyModels">
- <div class="form-group row mt-3 mb-2 d-flex justify-content-center">
-
- <div class="col-3">
- <label for="name" class="col-form-label">Naziv modela:</label>
- <input type="text" class="form-control" name="name" placeholder="Naziv..." [(ngModel)]="newModel.name">
- </div>
- <div class="col-5">
- <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
- <div>
- <textarea class="form-control" name="desc" rows="3" [(ngModel)]="newModel.description"></textarea>
- </div>
- </div>
-
- </div>
- <h2 class="mt-5 mb-4 mx-5">Parametri treniranja modela:</h2>
- <div>
-
- <div class="row p-2">
- <div class="col-1"></div>
- <div class="col-3">
- <label for="type" class="col-form-label">Tip problema: </label>
- </div>
- <div class="col-2">
- <select id=typeOptions class="form-select" name="type" [(ngModel)]="newModel.type"
- (change)="filterOptions()">
- <option
- *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col-1"></div>
- <div class="col-3">
- <label for="hiddenLayers" class="col-form-label">Broj skrivenih slojeva: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" class="form-control" name="hiddenLayers"
- [(ngModel)]="newModel.hiddenLayers"
- (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])"
- (ngModelChange)="updateGraph()">
- </div>
- </div>
-
- <div class="row p-2">
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="optimizer" class="col-form-label">Optimizacija: </label>
- </div>
- <div class="col-2">
- <select id=optimizerOptions class="form-select" name="optimizer" [(ngModel)]="newModel.optimizer">
- <option
- *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="hiddenLayerNeurons" class="col-form-label">Broj neurona skrivenih slojeva: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" class="form-control" name="hiddenLayerNeurons"
- [(ngModel)]="newModel.hiddenLayerNeurons" (ngModelChange)="updateGraph()">
- </div>
- </div>
-
- <div class="row p-2">
- <div class="col-1"></div>
- <div class="col-3">
- <label for="lossFunction" class="col-form-label">Funkcija troška: </label>
- </div>
- <div class="col-2">
- <select id=lossFunctionOptions class="form-select" name="lossFunction"
- [(ngModel)]="newModel.lossFunction" aria-checked="true">
- <option
- *ngFor="let option of Object.keys(lossFunction); let optionName of Object.values(lossFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col-1"></div>
- <div class="col-3">
- <label for="batchSize" class="col-form-label">Broj uzorka po iteraciji: </label>
- </div>
- <div class="col-1">
-
- <input type="number" min="0" step="1" max="7" class="form-control" name="batchSizePower" [(ngModel)]="batchSizePower" (click)="updateBatchSize()" >
- {{newModel.batchSize}}
-
- </div>
-
- <div class="row p-2">
- <div class="col-1"></div>
- <div class="col-3 m-1">
- <label for="epochs" class="col-form-label">Broj epoha: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" max="1000" class="form-control" name="epochs"
- [(ngModel)]="newModel.epochs">
- </div>
- </div>
- </div>
-
- <div class="m-5">
- <app-graph [model]="newModel" [inputCols]="1"></app-graph>
- </div>
-
- <h3 class="mx-5 mt-4">Aktivacione funkcije:</h3>
-
- <div class="row p-2" style="align-self: center;">
- <div class="col-1"></div>
- <div class="col-3">
- <label for="hiddenLayerActivationFunction" class="col-form-label"
- style="text-align: center;">Funkcija aktivacije<br>skrivenih slojeva:</label>
- </div>
- <div class="col-2 mt-2">
- <div *ngFor="let item of [].constructor(newModel.hiddenLayers); let i = index">
- <div class="input-group mb-2">
- <div class="input-group-prepend">
- <span class="input-group-text">#{{i+1}}</span>
- </div>
- <select [id]="'hiddenLayerActivationFunctionOption_'+i" class="form-select"
- [(ngModel)]="newModel.hiddenLayerActivationFunctions[i]" >
- <option
- *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- </div>
- </div>
- <div class="col-1"></div>
- <div class="col-2">
- <label for="outputLayerActivationFunction" class="col-form-label"
- style="text-align: center;">Funkcija aktivacije<br>izlaznog sloja:</label>
- </div>
- <div class="col-2 mt-2">
- <select id=outputLayerActivationFunctionOptions class="form-select"
- name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction">
- <option
- *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col">
- </div>
- </div>
- </div>
-
- <div class="form-check form-check-inline overflow-auto m-4" style="width: max-content;">
- <h3>Izaberite metrike:</h3>
- <div id="divMetricsinput" class="mt-2 mx-5">
-
- <div *ngFor="let option of Object.keys(metrics); let optionName of Object.values(metrics) "
- class="form-check form-check-inline">
-
- <input name="cbmetrics" class="form-check-input" type="checkbox" value="{{option}}"
- id="metrics_{{option}}" style="float: left;" checked>
- <label class="form-check-label" for="metrics_{{option}}" for="inlineCheckbox2">
- {{optionName}}
- </label>
- </div>
- </div>
- </div>
-
- <div class="form-group row mt-3 mb-3">
- <div class="col"></div>
- <button class="btn btn-lg col-4" style="background-color:#003459; color:white;"
- (click)="uploadModel();">Sačuvaj
- model</button>
- <div class="col"></div>
- </div>
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.ts b/frontend/src/app/_elements/model-load/model-load.component.ts
deleted file mode 100644
index dbca3d17..00000000
--- a/frontend/src/app/_elements/model-load/model-load.component.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { Component, OnInit, ViewChild, Output, EventEmitter, Input } from '@angular/core';
-import Shared from 'src/app/Shared';
-import Experiment from 'src/app/_data/Experiment';
-import Model, { ActivationFunction, LossFunction, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType } from 'src/app/_data/Model';
-import { ModelsService } from 'src/app/_services/models.service';
-import { GraphComponent } from '../graph/graph.component';
-
-
-@Component({
- selector: 'app-model-load',
- templateUrl: './model-load.component.html',
- styleUrls: ['./model-load.component.css']
-})
-export class ModelLoadComponent implements OnInit {
-
- @ViewChild(GraphComponent) graph!: GraphComponent;
- @Input() forExperiment?:Experiment;
- @Output() selectedModelChangeEvent = new EventEmitter<Model>();
-
- newModel: Model = new Model();
- myModels?: Model[];
- selectedModel?: Model;
-
- ProblemType = ProblemType;
- ActivationFunction = ActivationFunction;
- metrics: any = Metrics;
- LossFunction = LossFunction;
- Optimizer = Optimizer;
- Object = Object;
- document = document;
- shared = Shared;
-
- term: string = "";
- selectedProblemType: string = '';
- selectedMetrics = [];
- lossFunction: any = LossFunction;
-
- showMyModels: boolean = true;
-
- constructor(private modelsService: ModelsService) {
- this.modelsService.getMyModels().subscribe((models) => {
- this.myModels = models;
- });
- }
-
- ngOnInit(): void {
- }
- batchSizePower:number=1;
- updateBatchSize()
- {
- this.newModel.batchSize=2**this.batchSizePower;
- }
-
- updateGraph() {
- this.graph.update();
- }
-
- getMetrics() {
- this.newModel.metrics = [];
- let cb = document.getElementsByName("cbmetrics");
-
- for (let i = 0; i < cb.length; i++) {
- let chb = <HTMLInputElement>cb[i];
- if (chb.checked == true)
- this.newModel.metrics.push(chb.value);
- }
- }
-
- uploadModel() {
- this.getMetrics();
-
- this.newModel.uploaderId = Shared.userId;
-
- this.modelsService.addModel(this.newModel).subscribe((response) => {
- Shared.openDialog('Model dodat', 'Model je uspešno dodat u bazu.');
- // treba da se selektuje nov model u listi modela
- //this.selectedModel =
- }, (error) => {
- Shared.openDialog('Greška', 'Model sa unetim nazivom već postoji u Vašoj kolekciji. Promenite naziv modela i nastavite sa kreiranim datasetom.');
- });
- }
-
- filterOptions() {
- switch (this.newModel.type) {
- case 'regresioni':
- this.lossFunction = LossFunctionRegression;
- this.metrics = MetricsRegression;
- break;
- case 'binarni-klasifikacioni':
- this.lossFunction = LossFunctionBinaryClassification;
- this.metrics = MetricsBinaryClassification;
- break;
- case 'multi-klasifikacioni':
- this.lossFunction = LossFunctionMultiClassification;
- this.metrics = MetricsMultiClassification;
- break;
- default:
- break;
- }
- }
-
- viewMyModelsForm() {
- this.showMyModels = true;
- }
- viewNewModelForm() {
- this.showMyModels = false;
- }
-
- selectThisModel(model: Model) {
- this.selectedModel = model;
- this.selectedModelChangeEvent.emit(this.selectedModel);
- }
-
-}
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css
index e69de29b..e99a1e1e 100644
--- a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.css
@@ -0,0 +1,8 @@
+#btnYes {
+ background-color: var(--offwhite);
+ color: var(--ns-bg-dark-100);
+}
+
+#btnNo {
+ color: gray;
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html
index 7ba286cb..08c1f26b 100644
--- a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.html
@@ -1,16 +1,17 @@
-<h1 mat-dialog-title>Enkodiranje svih kolona</h1>
-<div mat-dialog-content>
- <p>Odaberite tip enkodinga za sve kolone zajedno:</p>
- <mat-form-field>
- <mat-select matNativeControl [(value)]="selectedEncodingType">
- <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>
- <p>Da li ste sigurni u izbor?</p>
+<h2 mat-dialog-title class="text-center">Enkodiranje svih kolona</h2>
+<div mat-dialog-content class="mt-5 mb-4">
+ <p>Sve izabrane kolone biće enkodirane metodom:</p>
+ <form (keydown)="withEnterKey($event)">
+ <mat-form-field>
+ <mat-select matNativeControl [(value)]="selectedEncodingType" cdkFocusInitial>
+ <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>
+ </form>
</div>
-<div mat-dialog-actions>
- <button mat-button [mat-dialog-close]="selectedEncodingType" cdkFocusInitial>Da</button>
- <button mat-button (click)="onNoClick()">Odustani</button>
+<div mat-dialog-actions class="justify-content-center">
+ <button id="btnYes" mat-stroked-button color="basic" (click)="onYesClick()">Potvrdi</button>
+ <button id="btnNo" mat-stroked-button (click)="onNoClick()">Odustani</button>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts
index 3b7560bf..9c45d7b6 100644
--- a/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts
+++ b/frontend/src/app/_modals/encoding-dialog/encoding-dialog.component.ts
@@ -1,7 +1,10 @@
import { Component, OnInit } from '@angular/core';
-import { MatDialogRef } from '@angular/material/dialog';
-import { Encoding } from 'src/app/_data/Experiment';
-
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ColumnType, Encoding } from 'src/app/_data/Experiment';
+import Experiment from 'src/app/_data/Experiment';
+import { ExperimentsService } from 'src/app/_services/experiments.service';
+import { Inject} from '@angular/core';
+import Dataset from 'src/app/_data/Dataset';
@Component({
selector: 'app-encoding-dialog',
@@ -13,6 +16,7 @@ export class EncodingDialogComponent implements OnInit {
selectedEncodingType?: Encoding;
Encoding = Encoding;
Object = Object;
+ categoricalColumnExists: boolean = true;
constructor(public dialogRef: MatDialogRef<EncodingDialogComponent>)
{
@@ -20,9 +24,19 @@ export class EncodingDialogComponent implements OnInit {
}
ngOnInit(): void {
+
}
onNoClick() {
this.dialogRef.close();
}
-}
+
+ withEnterKey(keyboardEvent: KeyboardEvent) {
+ if (keyboardEvent.code == "Enter" || keyboardEvent.code == "NumpadEnter")
+ this.onYesClick();
+ }
+
+ onYesClick() {
+ this.dialogRef.close(this.selectedEncodingType);
+ }
+}
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.html b/frontend/src/app/_modals/login-modal/login-modal.component.html
index cea6bf39..79e11db8 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.html
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.html
@@ -6,12 +6,12 @@
<mat-icon>close</mat-icon>
</button>
<h1 class="login-heading mt-5 mb-5">Prijava</h1>
- <form>
+ <form (keydown)="doLoginWithEnterKey($event)">
<!-- Korisnicko ime -->
<div class="mb-3">
<mat-form-field appearance="fill">
<mat-label>Korisničko ime</mat-label>
- <input type="text" matInput [(ngModel)]="username" name="username" id="username">
+ <input type="text" matInput [(ngModel)]="username" name="username" id="username" #usernameInput autofocus="true">
<mat-icon matSuffix></mat-icon>
</mat-form-field>
</div>
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.ts b/frontend/src/app/_modals/login-modal/login-modal.component.ts
index ccd78509..33c17c31 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.ts
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts
@@ -5,15 +5,17 @@ import { AuthService } from 'src/app/_services/auth.service';
import { UserInfoService } from 'src/app/_services/user-info.service';
import shared from '../../Shared';
import {AfterViewInit, ElementRef} from '@angular/core';
+import { MatSelect } from '@angular/material/select';
@Component({
selector: 'app-login-modal',
templateUrl: './login-modal.component.html',
styleUrls: ['./login-modal.component.css']
})
-export class LoginModalComponent implements OnInit {
+export class LoginModalComponent implements AfterViewInit {
@ViewChild('closeButton') closeButton?: ElementRef;
+ @ViewChild('usernameInput') usernameInput!: ElementRef;
@ViewChild('pass') passwordInput!: ElementRef;
username: string = '';
@@ -30,7 +32,14 @@ export class LoginModalComponent implements OnInit {
private userInfoService: UserInfoService
) { }
- ngOnInit(): void {
+ ngAfterViewInit(): void {
+ //console.log(this.usernameInput);
+ this.usernameInput.nativeElement.focus();
+ }
+
+ doLoginWithEnterKey(keyboardEvent: KeyboardEvent) {
+ if (keyboardEvent.code == "Enter" || keyboardEvent.code == "NumpadEnter")
+ this.doLogin();
}
doLogin() {
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css
index e69de29b..e99a1e1e 100644
--- a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.css
@@ -0,0 +1,8 @@
+#btnYes {
+ background-color: var(--offwhite);
+ color: var(--ns-bg-dark-100);
+}
+
+#btnNo {
+ color: gray;
+} \ No newline at end of file
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html
index 81aec5f8..7ab92d02 100644
--- a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.html
@@ -1,13 +1,13 @@
-<h1 mat-dialog-title>Popunjavanje nedostajućih vrednosti</h1>
-<div mat-dialog-content>
- <p>Želim da:</p>
- <mat-radio-group [(ngModel)]="selectedMissingValuesOption">
- <mat-radio-button [value]="NullValueOptions.DeleteColumns" checked>obrišem sve kolone koje sadrže nedostajuće vrednosti</mat-radio-button>
- <mat-radio-button [value]="NullValueOptions.DeleteRows">obrišem sve redove koji sadrže nedostajuće vrednosti</mat-radio-button>
- </mat-radio-group>
- <p>Da li ste sigurni u izbor?</p>
+<h2 mat-dialog-title class="text-center">Nedostajuće vrednosti</h2>
+<div mat-dialog-content class="mt-5 mb-4">
+ <form (keydown)="withEnterKey($event)">
+ <mat-radio-group [(ngModel)]="selectedMissingValuesOption" [ngModelOptions]="{standalone: true}">
+ <mat-radio-button [value]="NullValueOptions.DeleteColumns" checked>Obriši sve kolone koje sadrže nedostajuće vrednosti</mat-radio-button>
+ <mat-radio-button [value]="NullValueOptions.DeleteRows">Obriši sve redove koji sadrže nedostajuće vrednosti</mat-radio-button>
+ </mat-radio-group>
+ </form>
</div>
-<div mat-dialog-actions>
- <button mat-button [mat-dialog-close]="selectedMissingValuesOption" cdkFocusInitial>Da</button>
- <button mat-button (click)="onNoClick()">Odustani</button>
+<div mat-dialog-actions class="justify-content-center">
+ <button id="btnYes" mat-stroked-button color="basic" (click)="onYesClick()">Potvrdi</button>
+ <button id="btnNo" mat-stroked-button (click)="onNoClick()">Odustani</button>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts
index 908edd9e..822d4e4a 100644
--- a/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts
+++ b/frontend/src/app/_modals/missingvalues-dialog/missingvalues-dialog.component.ts
@@ -25,4 +25,12 @@ export class MissingvaluesDialogComponent implements OnInit {
this.dialogRef.close();
}
+ withEnterKey(keyboardEvent: KeyboardEvent) {
+ if (keyboardEvent.code == "Enter" || keyboardEvent.code == "NumpadEnter")
+ this.onYesClick();
+ }
+ onYesClick() {
+ this.dialogRef.close(this.selectedMissingValuesOption);
+ }
+
}
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.html b/frontend/src/app/_modals/register-modal/register-modal.component.html
index d76af4d6..0c791a61 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.html
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.html
@@ -6,7 +6,7 @@
<mat-icon>close</mat-icon>
</button>
<h1 class="mt-5 mb-4">Registracija</h1>
- <form class="mx-4">
+ <form class="mx-4" (keydown)="doRegisterWithEnterKey($event)">
<!--Ime-->
<div>
<mat-form-field appearance="fill">
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.ts b/frontend/src/app/_modals/register-modal/register-modal.component.ts
index 9da5484d..a5c6ddc6 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.ts
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts
@@ -49,6 +49,11 @@ export class RegisterModalComponent implements OnInit {
ngOnInit(): void {
}
+ doRegisterWithEnterKey(keyboardEvent: KeyboardEvent) {
+ if (keyboardEvent.code == "Enter" || keyboardEvent.code == "NumpadEnter")
+ this.doRegister();
+ }
+
doRegister() {
this.validation();
}
@@ -150,7 +155,9 @@ export class RegisterModalComponent implements OnInit {
username: this.username,
password: this.pass1,
email: this.email,
- photoId: "1"
+ photoId: "1",
+ isPermament:true,
+ dateCreated:new Date()
}
this.authService.register(user)
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
index e69de29b..8225af36 100644
--- 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
@@ -0,0 +1,13 @@
+#btnYes {
+ background-color: var(--offwhite);
+ color: var(--ns-bg-dark-100);
+}
+
+#btnNo {
+ color: gray;
+}
+
+.wrongInput {
+ color: var(--ns-warn);
+ font-size: 11px;
+} \ No newline at end of file
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
index bac73e0a..2b3678ce 100644
--- 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
@@ -1,13 +1,15 @@
-<h1 mat-dialog-title>Čuvanje eksperimenta</h1>
-<div mat-dialog-content>
- <span>Unesi naziv eksperimenta:</span>
- <mat-form-field>
- <input type="text" matInput [(ngModel)]="selectedName">
- </mat-form-field>
- <br><br>
- <p>Sačuvaj eksperiment:</p>
+<h1 mat-dialog-title class="text-center">Sačuvaj eksperiment</h1>
+<div mat-dialog-content class="mt-5 mb-4 mx-1">
+ <form (keydown)="saveWithEnterKey($event)">
+ Naziv eksperimenta:<br>
+ <mat-form-field [style.width.px]=250>
+ <input type="text" matInput [(ngModel)]="selectedName" cdkFocusInitial [ngModelOptions]="{standalone: true}">
+ </mat-form-field>
+ <p *ngIf="wrongAlreadyExists" class="wrongInput">Izaberi drugi naziv za eskperiment.<br>Eskperiment sa unetim nazivom već postoji u kolekciji.</p>
+ <p *ngIf="wrongEmptyName" class="wrongInput">Unesite naziv eksperimenta.</p>
+ </form>
</div>
-<div mat-dialog-actions>
- <button mat-button [mat-dialog-close]="selectedName" cdkFocusInitial>Da</button>
- <button mat-button (click)="onNoClick()">Odustani</button>
+<div mat-dialog-actions class="justify-content-center">
+ <button id="btnYes" mat-stroked-button color="basic" (click)="onYesClick()">Sačuvaj</button>
+ <button id="btnNo" mat-stroked-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.ts b/frontend/src/app/_modals/save-experiment-dialog/save-experiment-dialog.component.ts
index ca01f57e..3c19e732 100644
--- 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
@@ -1,5 +1,12 @@
import { Component, OnInit } from '@angular/core';
-import { MatDialogRef } from '@angular/material/dialog';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import Experiment from 'src/app/_data/Experiment';
+import { ExperimentsService } from 'src/app/_services/experiments.service';
+import { Inject} from '@angular/core';
+
+interface DialogData {
+ experiment: Experiment;
+}
@Component({
selector: 'app-save-experiment-dialog',
@@ -9,8 +16,13 @@ import { MatDialogRef } from '@angular/material/dialog';
export class SaveExperimentDialogComponent implements OnInit {
selectedName: string = '';
+ wrongAlreadyExists: boolean = false;
+ wrongEmptyName: boolean = false;
- constructor(public dialogRef: MatDialogRef<SaveExperimentDialogComponent>) { }
+ constructor(public dialogRef: MatDialogRef<SaveExperimentDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: DialogData, private experimentService: ExperimentsService) {
+ this.wrongAlreadyExists = false;
+ this.wrongEmptyName = false;
+ }
ngOnInit(): void {
}
@@ -18,4 +30,27 @@ export class SaveExperimentDialogComponent implements OnInit {
onNoClick() {
this.dialogRef.close();
}
+
+ saveWithEnterKey(keyboardEvent: KeyboardEvent) {
+ if (keyboardEvent.code == "Enter" || keyboardEvent.code == "NumpadEnter")
+ this.onYesClick();
+ }
+ onYesClick() {
+ if (this.selectedName == "") {
+ this.wrongEmptyName = true;
+ return;
+ }
+ this.wrongEmptyName = false;
+
+ this.data.experiment.name = this.selectedName;
+ this.experimentService.addExperiment(this.data.experiment).subscribe((response) => {
+ this.wrongAlreadyExists = false;
+ this.data.experiment = response;
+ this.dialogRef.close(this.data.experiment);
+ }, (error) => {
+ if (error.error == "Experiment with this name exists") {
+ this.wrongAlreadyExists = true;
+ }
+ });
+ }
}
diff --git a/frontend/src/app/_pages/archive/archive.component.html b/frontend/src/app/_pages/archive/archive.component.html
index fc3c4763..f9cce56b 100644
--- a/frontend/src/app/_pages/archive/archive.component.html
+++ b/frontend/src/app/_pages/archive/archive.component.html
@@ -1,5 +1,5 @@
<div class="d-flex flex-column align-items-center my-5">
- <app-folder></app-folder>
+ <app-folder [archive]="true" [startingTab]="TabType.MyExperiments"></app-folder>
<!--<div class="my-5" style="height: fit-content;">
<app-playlist [datasets]="publicDatasets"></app-playlist>
diff --git a/frontend/src/app/_pages/archive/archive.component.ts b/frontend/src/app/_pages/archive/archive.component.ts
index 47f96218..bb4bd9e9 100644
--- a/frontend/src/app/_pages/archive/archive.component.ts
+++ b/frontend/src/app/_pages/archive/archive.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import Dataset from 'src/app/_data/Dataset';
+import { TabType } from 'src/app/_elements/folder/folder.component';
import { DatasetsService } from 'src/app/_services/datasets.service';
@Component({
@@ -10,6 +11,7 @@ import { DatasetsService } from 'src/app/_services/datasets.service';
export class ArchiveComponent implements OnInit {
publicDatasets: Dataset[] = [];
+ TabType = TabType;
constructor(private datasetsService: DatasetsService) { }
diff --git a/frontend/src/app/_pages/experiment/experiment.component.css b/frontend/src/app/_pages/experiment/experiment.component.css
index 36c35484..4c063f87 100644
--- a/frontend/src/app/_pages/experiment/experiment.component.css
+++ b/frontend/src/app/_pages/experiment/experiment.component.css
@@ -52,4 +52,16 @@ mat-stepper {
width: 98%;
height: 98%;
overflow-y: auto;
-} \ No newline at end of file
+}
+.ekspName{
+ font-weight: bold;
+ font-size: large;
+}
+
+
+.addedElement{
+ color:var(--ns-accent);
+}
+.text-overflow {
+ overflow-wrap: break-word;
+}
diff --git a/frontend/src/app/_pages/experiment/experiment.component.html b/frontend/src/app/_pages/experiment/experiment.component.html
index 2b32db81..a2ede838 100644
--- a/frontend/src/app/_pages/experiment/experiment.component.html
+++ b/frontend/src/app/_pages/experiment/experiment.component.html
@@ -1,28 +1,48 @@
<div class="container-fluid p-0 text-offwhite holder" style="height: calc(100vh - 64px); text-align: center;">
<div class="d-flex flex-colum align-items-center sidenav">
+ <div>
+ <div class="ekspName " style="width: 250px;">
+ <div class="text-overflow" *ngIf="experiment.name=='exp1'" style="width: 250px;">
+ Novi Eksperiment
+ </div>
+ <div class="text-overflow" *ngIf="experiment.name!='exp1'" style="width: 250px;">
+ {{experiment.name}}
+ </div>
+
+ </div>
<mat-stepper orientation="vertical" (selectionChange)="changePage($event)">
<mat-step>
<!--editable="false"-->
- <ng-template matStepLabel><span class="label">Izvor podataka</span></ng-template>
+ <ng-template matStepLabel>
+ <span class="label" *ngIf="dataset==undefined">Izvor podataka</span>
+ <span class="label addedElement" *ngIf="dataset!=undefined">{{dataset.name}}</span>
+ </ng-template>
<ng-template matStepContent>
- <p>Izaberite vas izvor podataka</p>
+ <p class="text-left">Izaberite vas izvor podataka</p>
</ng-template>
</mat-step>
<mat-step>
- <ng-template matStepLabel> <span class="label">Odabir kolona</span></ng-template>
+ <ng-template matStepLabel>
+ <span class="label addedElement" *ngIf="experiment.name!='exp1'">Predvideti:{{experiment.outputColumn}}</span>
+ <span class="label" *ngIf="experiment.name=='exp1'">Odabir kolona</span>
+ </ng-template>
<ng-template matStepContent>
- <p>Pripremite podatke i izaberite izlazne kolone</p>
+ <p class="text-left">Pripremite podatke i izaberite izlazne kolone</p>
</ng-template>
</mat-step>
<mat-step>
- <ng-template matStepLabel><span class="label">Treniranje</span></ng-template>
- <p>Odaberite parametre i trenirajte model</p>
+ <ng-template matStepLabel>
+ <span class="label addedElement" *ngIf="modelToTrain!=undefined">{{modelToTrain.name}}</span>
+ <span class="label" *ngIf="modelToTrain==undefined">Treniranje</span>
+ </ng-template>
+ <p class="text-left">Odaberite parametre i trenirajte model</p>
</mat-step>
<mat-step>
<ng-template matStepLabel><span class="label">Pregled rezultata treniranja</span></ng-template>
- <p>Pregledajte tok treniranja i grafički prikaz rezultata</p>
+ <p class="text-left">Pregledajte tok treniranja i grafički prikaz rezultata</p>
</mat-step>
</mat-stepper>
+ </div>
</div>
<div #stepsContainer class="steps-container">
<div #steps id="step_1" class="step-content">
@@ -32,7 +52,7 @@
</div>
<div #steps id="step_2" class="step-content">
<div class="step-content-inside">
- <app-column-table (okPressed)="goToPage(2); experiment._columnsSelected = true;" (columnTableChanged)="columnTableChangedEvent()" [experiment]="experiment" [dataset]="dataset"></app-column-table>
+ <app-column-table (okPressed)="goToPage(2); experiment._columnsSelected = true;" (columnTableChanged)="columnTableChangedEvent()" (experimentChanged)="experimentChangedEvent()" [experiment]="experiment" [dataset]="dataset"></app-column-table>
</div>
</div>
<div #steps id="step_3" class="step-content">
@@ -46,4 +66,4 @@
</div>
</div>
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/frontend/src/app/_pages/experiment/experiment.component.ts b/frontend/src/app/_pages/experiment/experiment.component.ts
index 1dc18a78..abf4b697 100644
--- a/frontend/src/app/_pages/experiment/experiment.component.ts
+++ b/frontend/src/app/_pages/experiment/experiment.component.ts
@@ -147,12 +147,17 @@ export class ExperimentComponent implements AfterViewInit {
//console.log("promenio se column-table");
}
+ experimentChangedEvent() {
+ this.folderModel.updateExperiment();
+ }
+
setDataset(dataset: FolderFile) {
const d = <Dataset>dataset;
this.experiment.datasetId = d._id;
this.dataset = d;
this.columnTable.loadDataset(this.dataset);
+
}
modelToTrain?: Model;
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
deleted file mode 100644
index 66b3755e..00000000
--- a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { DatasetsService } from 'src/app/_services/datasets.service';
-import Dataset from 'src/app/_data/Dataset';
-import {Router} from '@angular/router'
-import { JwtHelperService } from '@auth0/angular-jwt';
-import { CookieService } from 'ngx-cookie-service';
-import shared from 'src/app/Shared';
-
-@Component({
- selector: 'app-filter-datasets',
- templateUrl: './filter-datasets.component.html',
- styleUrls: ['./filter-datasets.component.css']
-})
-export class FilterDatasetsComponent implements OnInit {
-
- shared = shared;
- publicDatasets?: Dataset[];
- term: string = "";
- constructor(private datasets: DatasetsService,private router:Router, private cookie: CookieService) {
- this.datasets.getPublicDatasets().subscribe((datasets) => {
- this.publicDatasets = datasets;
- });
- }
-
- ngOnInit(): void {
-
- }
- addDataset(dataset: Dataset):void{
- //this.router.navigateByUrl('/predict?id='+id);
- const helper = new JwtHelperService();
- const decodedToken = helper.decodeToken(this.cookie.get("token"));
- const newDataset={...dataset};
- newDataset._id = "";
- newDataset.isPublic = false;
- newDataset.lastUpdated = new Date();
- newDataset.uploaderId = decodedToken.uploaderId;
- let name=prompt("Unesite naziv dataset-a",newDataset.name);
- newDataset.name=name as string;
- if(name!=null && name!="")
- this.datasets.addDataset(newDataset).subscribe((response:string)=>{
- shared.openDialog("Obaveštenje", "Uspešno ste dodali dataset sa nazivom " + newDataset.name);
- },(error)=>{
- shared.openDialog("Obaveštenje", "U svojoj kolekciji već imate dataset sa ovim imenom. Molimo Vas da unesete drugo ime.");
- });
-
- };
-
-}
diff --git a/frontend/src/app/_pages/profile/profile.component.css b/frontend/src/app/_pages/profile/profile.component.css
index 428870da..bbd4c9ba 100644
--- a/frontend/src/app/_pages/profile/profile.component.css
+++ b/frontend/src/app/_pages/profile/profile.component.css
@@ -1,21 +1,25 @@
-.card{
+.card {
background-color: transparent;
- color:var(--offwhite)
+ color: var(--offwhite)
}
-.card-header{
+.card-header {
background-color: var(--ns-primary-50);
- color:var(--offwhite)
+ color: var(--offwhite)
}
-.card-body{
+
+.card-body {
background-color: var(--ns-bg-dark-50);
}
-mat-form-field{
+mat-form-field {
width: 100%;
}
-.danger-Text{
- color:var(--ns-warn)
+.danger-Text {
+ color: var(--ns-warn)
}
+.selectedPicture {
+ background-color: var(--ns-accent);
+} \ No newline at end of file
diff --git a/frontend/src/app/_pages/profile/profile.component.html b/frontend/src/app/_pages/profile/profile.component.html
index 37df4f14..8d655513 100644
--- a/frontend/src/app/_pages/profile/profile.component.html
+++ b/frontend/src/app/_pages/profile/profile.component.html
@@ -12,7 +12,7 @@
<img class="img-account-profile rounded-circle mb-2" src="{{this.photoPath}}" alt="profilePicture">
<!-- User's info -->
<span>@ {{this.user.username}}</span>
- <span class="mt-3" style="font-weight: bold;">{{this.user.firstName}} {{this.user.lastName}}</span>
+ <span class="mt-3" style="font-weight: bold;">{{this.user.firstName}} {{this.user.lastName}}</span>
</div>
</div>
</div>
@@ -31,7 +31,7 @@
<mat-form-field appearance="fill">
<mat-label>Važeća lozinka</mat-label>
<input matInput id="inputPassword" name="inputPassword" type="password" placeholder="" [(ngModel)]="this.oldPass">
- </mat-form-field>
+ </mat-form-field>
<small *ngIf="wrongOldPassBool" class="form-text danger-Text">Pogrešan format.</small>
</div>
<!-- Form Group (new password)-->
@@ -39,12 +39,12 @@
<mat-form-field appearance="fill">
<mat-label>Nova lozinka</mat-label>
<input matInput id="inputNewPassword" name="inputNewPassword" type="password" placeholder="" [(ngModel)]="this.newPass1">
- </mat-form-field>
+ </mat-form-field>
<small *ngIf="wrongNewPassBool" class="form-text danger-Text">Lozinke se ne podudaraju.</small>
<small *ngIf="wrongNewPass1Bool" class="form-text danger-Text">Pogrešan format.</small>
</div>
</div>
-
+
<!-- Form Row-->
<div class="row gx-3 mb-3">
<div class="col-md-6">
@@ -118,24 +118,23 @@
<div>
<label class="small mt-2 mb-3">Kliknite na sliku kako biste je odabrali za profilnu:</label>
-
+
<div class="container">
<div class="card-group">
<!--bootstrap card with 3 horizontal images-->
<div class="row overflow-auto" style="max-height: 200px;">
- <div class="card col-md-3" *ngFor="let picture of this.pictures" (click)="this.photoId = picture.photoId.toString()"
- [ngClass]="{'selectedPicture': this.photoId == picture.photoId.toString()}">
+ <div class="card col-md-3" *ngFor="let picture of this.pictures" (click)="this.photoId = picture.photoId.toString()" [ngClass]="{'selectedPicture': this.photoId == picture.photoId.toString()}">
<img src="{{picture.path}}">
</div>
</div>
</div>
</div>
</div>
-
+
<div class="row mt-5">
<div class="col text-center">
<!-- Save changes button-->
- <button mat-raised-button color="primary" (click)="saveInfoChanges()" >Sačuvaj izmene</button>
+ <button mat-raised-button color="primary" (click)="saveInfoChanges()">Sačuvaj izmene</button>
</div>
</div>
</form>
@@ -147,7 +146,7 @@
<div class="row">
<div class="col-xl-4">
-
+
</div>
</div>
diff --git a/frontend/src/app/_pages/profile/profile.component.ts b/frontend/src/app/_pages/profile/profile.component.ts
index ae9fb12c..fdcd347c 100644
--- a/frontend/src/app/_pages/profile/profile.component.ts
+++ b/frontend/src/app/_pages/profile/profile.component.ts
@@ -28,6 +28,8 @@ export class ProfileComponent implements OnInit {
newPass2: string = '';
photoId: string = '';
photoPath: string = '';
+ isPermament:boolean=false;
+ dateCreated:Date=new Date();
wrongPassBool: boolean = false;
wrongNewPassBool: boolean = false;
@@ -60,6 +62,9 @@ export class ProfileComponent implements OnInit {
this.firstName = this.user.firstName;
this.lastName = this.user.lastName;
this.photoId = this.user.photoId;
+ this.dateCreated=this.user.dateCreated;
+ this.isPermament=this.user.isPermament;
+
for (let i = 0; i < this.pictures.length; i++) {
if (this.pictures[i].photoId.toString() === this.photoId) {
@@ -81,7 +86,9 @@ export class ProfileComponent implements OnInit {
password: this.user.password,
firstName: this.firstName,
lastName: this.lastName,
- photoId: this.photoId
+ photoId: this.photoId,
+ isPermament:this.isPermament,
+ dateCreated:this.dateCreated
}
this.userInfoService.changeUserInfo(editedUser).subscribe((response: any) =>{
diff --git a/frontend/src/app/_pages/settings/settings.component.css b/frontend/src/app/_pages/settings/settings.component.css
deleted file mode 100644
index e69de29b..00000000
--- a/frontend/src/app/_pages/settings/settings.component.css
+++ /dev/null
diff --git a/frontend/src/app/_pages/settings/settings.component.html b/frontend/src/app/_pages/settings/settings.component.html
deleted file mode 100644
index 4ab2a415..00000000
--- a/frontend/src/app/_pages/settings/settings.component.html
+++ /dev/null
@@ -1 +0,0 @@
-<p>settings works!</p>
diff --git a/frontend/src/app/_pages/settings/settings.component.spec.ts b/frontend/src/app/_pages/settings/settings.component.spec.ts
deleted file mode 100644
index a3a508b0..00000000
--- a/frontend/src/app/_pages/settings/settings.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { SettingsComponent } from './settings.component';
-
-describe('SettingsComponent', () => {
- let component: SettingsComponent;
- let fixture: ComponentFixture<SettingsComponent>;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ SettingsComponent ]
- })
- .compileComponents();
- });
-
- beforeEach(() => {
- fixture = TestBed.createComponent(SettingsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/frontend/src/app/_pages/settings/settings.component.ts b/frontend/src/app/_pages/settings/settings.component.ts
deleted file mode 100644
index 19862fb0..00000000
--- a/frontend/src/app/_pages/settings/settings.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-settings',
- templateUrl: './settings.component.html',
- styleUrls: ['./settings.component.css']
-})
-export class SettingsComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit(): void {
- }
-
-}
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
index d15793e7..fb0b0223 100644
--- a/frontend/src/app/app.component.html
+++ b/frontend/src/app/app.component.html
@@ -7,7 +7,7 @@
</app-reactive-background>
<app-navbar></app-navbar>
<a class="bg-controls" style="z-index: 1000;" routerLink="playground">
- <mat-icon color="accent">settings_suggest</mat-icon>
+ <mat-icon color="primary">settings_suggest</mat-icon>
</a>
<router-outlet></router-outlet>
<app-notifications></app-notifications> \ No newline at end of file
diff --git a/frontend/src/app/experiment/experiment.component.html b/frontend/src/app/experiment/experiment.component.html
deleted file mode 100644
index 62236cce..00000000
--- a/frontend/src/app/experiment/experiment.component.html
+++ /dev/null
@@ -1,255 +0,0 @@
-<div id="header">
- <h1>Napravite svoju veštačku neuronsku mrežu</h1>
-</div>
-<div id="wrapper">
- <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
-
- <div class="d-flex flex-row justify-content-center align-items-center my-3">
- <a href="#" data-bs-target="#carouselExampleControls" data-bs-slide-to="0">Izvor podataka</a>
- <mat-icon>arrow_forward</mat-icon>
- <a href="#" data-bs-target="#carouselExampleControls" data-bs-slide-to="1">Preprocesiranje</a>
- <mat-icon>arrow_forward</mat-icon>
- <a href="#" data-bs-target="#carouselExampleControls" data-bs-slide-to="2">Dodaj eksperiment</a>
- </div>
-
- <div id="carouselExampleControls" class="carousel slide px-5 mt-5" data-bs-wrap="false" data-bs-ride="carousel" data-bs-interval="false">
- <div class="carousel-inner">
- <div class="carousel-item active mt-2">
- <h2 class="mb-5">1. Izvor podataka</h2>
- <app-dataset-load (selectedDatasetChangeEvent)="updateDataset($event)"></app-dataset-load>
- </div>
-
- <div class="carousel-item mt-2">
- <h2 class="mb-4">2. Preprocesiranje</h2>
-
- <div class="px-5">
- <h3>Biranje ulaznih i izlaznih kolona:</h3>
- <div *ngIf="selectedDataset">
- <div class="row">
- <div class="col d-flex justify-content-center">
- <h3>Izaberite ulazne kolone:</h3>
- <div id="divInputs" class="form-check mt-2">
- <br>
- <div *ngFor="let item of selectedDataset.columnInfo; let i = index">
- <input class="form-check-input" type="checkbox" value="{{item.columnName}}" id="cb_{{item.columnName}}" name="cbsNew" [checked]="experiment.outputColumn != item.columnName" [disabled]="experiment.outputColumn == item.columnName" (change)="checkedColumnsChanged(item, 0); resetColumnEncodings();">&nbsp;
- <label class="form-check-label" for="cb_{{item.columnName}}">
- {{item.columnName}}
- </label>
- </div>
- </div>
- </div>
- <div class="col d-flex justify-content-left">
- <h3>Izaberite izlaznu kolonu:</h3>
- <div id="divOutputs" class="form-check mt-2">
- <br>
- <div *ngFor="let item of selectedDataset.columnInfo; let i = index">
- <input class="form-check-input" type="radio" value="{{item.columnName}}" id="rb_{{item.columnName}}" name="rbsNew" [(ngModel)]="this.experiment.outputColumn" (change)="experiment.outputColumn = item.columnName; checkedColumnsChanged(item, 1); resetColumnEncodings();"
- checked>&nbsp;
- <label class="form-check-label" for="rb_{{item.columnName}}">
- {{item.columnName}}
- </label>
- </div>
- </div>
- </div>
- </div>
- </div>
-
-
- <div class="mt-5 mb-3 mx-3" *ngIf="countSelectedNullCols() == 0">
- <h3 class="border p-2 text-center"><i>Izabrane kolone nemaju nedostajuće vrednosti koje možete popuniti.</i></h3>
- </div>
-
- <div *ngIf="countSelectedNullCols() != 0">
- <h3 class="mt-5">Popunjavanje nedostajućih vrednosti:</h3>
- <div class="form-check" *ngIf="selectedDataset">
- <input type="radio" [(ngModel)]="experiment.nullValues " [value]="NullValueOptions.DeleteRows " class="form-check-input" value="deleteRows" name="fillMissing " id="delRows" checked data-bs-toggle="collapse" data-bs-target="#fillMissingCustom.show">
- <label for="delRows" class="form-check-label ">Obriši sve
- redove sa nedostajućim vrednostima ({{selectedDataset.nullRows}} od {{selectedDataset.rowCount}})</label><br>
- <input type="radio" [(ngModel)]="experiment.nullValues " [value]="NullValueOptions.DeleteColumns " class="form-check-input" value="deleteCols" name="fillMissing " id="delCols" data-bs-toggle="collapse" data-bs-target="#fillMissingCustom.show">
- <label for="delCols" class="form-check-label ">Obriši sve
- kolone sa nedostajućim vrednostima ({{countSelectedNullCols()}} od {{selectedDataset.columnInfo.length}})</label><br>
- <input type="radio" [(ngModel)]="experiment.nullValues " [value]="NullValueOptions.Replace " class="form-check-input" name="fillMissing" id="replace" data-bs-toggle="collapse" data-bs-target="#fillMissingCustom:not(.show)">
- <label for="replace" class="form-check-label">Izabraću
- vrednosti koje će da zamene nedostajuće vrednosti za svaku kolonu...</label><br><br>
- <div class="collapse" id="fillMissingCustom">
- <div>
- <label for="columnReplacers" class="form-label">Unesite zamenu za svaku kolonu:</label>
- <div class="my-3 " *ngIf="getSelectedColumnsArrayWithoutNullVals().length> 0">
- <label class="text-center form-control mx-3 text-secondary">
- Kolone <span style="font-style: italic;" *ngFor="let colname of getSelectedColumnsArrayWithoutNullVals(); let i = index">
- <span *ngIf="i != getSelectedColumnsArrayWithoutNullVals().length - 1">{{colname}}, </span>
- <span *ngIf="i == getSelectedColumnsArrayWithoutNullVals().length - 1">{{colname}} </span>
- </span>
- nemaju nedostajućih vrednosti za popunjavanje.
- </label>
- </div>
- <div id="columnReplacers">
- <div *ngFor="let column of selectedColumnsInfoArray; let i = index" class="my-3">
- <div *ngIf="column.numNulls > 0">
- <span class="w-20 mx-3">
- {{column.columnName}}&nbsp;
- <span class="small" style="color:gray;">({{column.numNulls}} null)</span>
- </span>
-
- <div class="d-flex flex-row justify-content-end">
- <div class="flex-grow-3 mx-3 me-auto">
- <div class="input-group">
- <div class="input-group-prepend">
- <label [for]="'fillCol_'+column.columnName" class="form-control">
- Zameni
- <input type="radio" [id]="'fillCol_'+column.columnName"
- [name]="'delOp_'+column.columnName">
- </label>
- </div>
- <input type="text" class="form-control" [id]="'fillText_'+column.columnName" (keyup)="checkFillColRadio(column.columnName)" placeholder="Unesi vrednost...">
-
- <div class="input-group-append">
- <select [id]="'replaceOptions'+i" class="form-control btn-primary" *ngIf="column.isNumber" (change)="replace($event, column); checkFillColRadio(column.columnName);">
- <option
- *ngFor="let option of Object.keys(ReplaceWith); let optionName of Object.values(ReplaceWith)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- <select [id]="'replaceOptions'+i" class="form-control btn-outline-primary" *ngIf="!column.isNumber && column.numNulls > 0" (change)="replace($event, column); checkFillColRadio(column.columnName);">
- <option *ngFor="let option of column.uniqueValues" [value]="option">
- {{ option }}
- </option>
- </select>
- </div>
- </div>
- </div>
-
- <div class="flex-shrink-1 mx-3">
- <div class="input-group">
- <label class="form-control" [for]="'delCol_'+column.columnName">Izbriši
- kolonu
- <input type="radio" [id]="'delCol_'+column.columnName"
- [name]="'delOp_'+column.columnName"
- (change)="emptyFillTextInput(column.columnName)"></label>
- </div>
- </div>
-
- <div class="flex-shrink-1 mx-3">
- <div class="input-group">
- <label class="form-control" [for]="'delRows_'+column.columnName">Izbriši
- redove
- <input type="radio" [id]="'delRows_'+column.columnName"
- [name]="'delOp_'+column.columnName" checked
- (change)="emptyFillTextInput(column.columnName)"></label>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div id="randomOptions" class="mt-5">
- <div class="p-2 m-2">
- <label for="type" class="form-check-label">Želite li da redosled podataka bude nasumičan?</label>
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="experiment.randomOrder" type="checkbox" value="" checked>
- </div>
- <div class="border m-3">
- <div class="row p-2 m-2">
- <div class="col-4">
- <label for="splitYesNo" class="form-check-label">
- <h3>Podela test skupa:&nbsp;&nbsp;
- <input id="splitYesNo" class="form-check-input" type="checkbox"
- [checked]="experiment.randomTestSet"
- (change)="experiment.randomTestSet = !experiment.randomTestSet">
- </h3>
- </label>
- </div>
- <div class="col-8">
- trening
- <mat-slider style="width: 85%;" min="10" max="90" step="10" value="10" name="randomTestSetDistribution" thumbLabel [disabled]="!experiment.randomTestSet" [(ngModel)]="tempTestSetDistribution">
- </mat-slider>
- test
- </div>
- </div>
-
- <div class="row p-2 m-2">
- <label for="percentage" class="form-label">Procenat podataka koji se uzima za trening
- skup:</label>
- <input id="percentage" type="number" class="form-control mx-3" style=" max-width: 15%" min="10" max="90" step="10" value="90" [(ngModel)]="tempTestSetDistribution" [disabled]="!experiment.randomTestSet">
- </div>
- </div>
- </div>
-
- <div id="encodingsForColumns" class="px-3 my-5">
- <label for="encoding" class="col-form-label mb-2">Enkoding za izabrane kolone:</label>
-
- <div class="row d-flex flex-row justify-content-between align-items-center">
- <div class="col-5" *ngFor="let item of [].constructor(selectedColumnsInfoArray.length); let i = index">
- <div class="input-group mb-2">
- <div class="input-group-prepend">
- <span class="input-group-text">{{selectedColumnsInfoArray[i].columnName}}</span>
- </div>
- <select [id]="'encodingOption_'+i" class="form-select" [(ngModel)]="experiment.encodings[i].encoding">
- <option
- *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- </div>
- </div>
- </div>
-
- </div>
-
-
- </div>
-
- <div class="carousel-item mt-2">
- <h2 class="mb-4">3. Dodaj eskperiment</h2>
-
- <div class="row">
- <div class="col"></div>
- <div class="col-8">
- <label for="name" class="col-form-label">Naziv eksperimenta:</label>
- <input type="text" class="form-control mb-3" name="name" placeholder="Naziv..." [(ngModel)]="experiment.name">
-
- <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
- <div>
- <textarea class="form-control" name="desc" rows="3" [(ngModel)]="experiment.description"></textarea>
- </div>
- <label for="desc" class="col-sm-2 col-form-label mt-3">Tip problema:</label>
- <div class="col-4">
- <select id="typeOptions" class="form-select" name="type" [(ngModel)]="experiment.type">
- <option
- *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="form-group row mt-5 mb-3">
- <div class="col"></div>
- <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="saveExperiment();">Sačuvaj
- eksperiment</button>
- <div class="col"></div>
- </div>
- </div>
- <div class="col"></div>
- </div>
- </div>
-
- </div>
-
- <div class="m-3 d-flex flex-row justify-content-between align-items-center" style=" margin-left: auto;">
- <button mat-fab color="primary" data-bs-target="#carouselExampleControls" data-bs-slide="prev">
- <mat-icon>arrow_backward</mat-icon>
- </button>
- <button mat-fab color="primary" data-bs-target="#carouselExampleControls" data-bs-slide="next">
- <mat-icon>arrow_forward</mat-icon>
- </button>
- </div>
- </div>
- </div>
-</div> \ No newline at end of file
diff --git a/frontend/src/app/experiment/experiment.component.ts b/frontend/src/app/experiment/experiment.component.ts
deleted file mode 100644
index 2d0f6ec5..00000000
--- a/frontend/src/app/experiment/experiment.component.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import Experiment, { NullValReplacer, NullValueOptions, ReplaceWith, Encoding } from '../_data/Experiment';
-import Model,{ProblemType} from '../_data/Model';
-import Dataset, { ColumnInfo } from '../_data/Dataset';
-import { ModelsService } from '../_services/models.service';
-import Shared from '../Shared';
-import { ExperimentsService } from '../_services/experiments.service';
-import { ColumnEncoding } from '../_data/Experiment';
-
-@Component({
- selector: 'app-experiment',
- templateUrl: './experiment.component.html',
- styleUrls: ['./experiment.component.css']
-})
-export class ExperimentComponent implements OnInit {
-
- experiment: Experiment = new Experiment();
- selectedModel?: Model;
- selectedDataset?: Dataset;
- trainingResult: any; // any za sad, promeni kasnije
-
- NullValueOptions = NullValueOptions;
- ReplaceWith = ReplaceWith;
- Encoding = Encoding;
- ColumnEncoding = ColumnEncoding;
- Object = Object;
- ProblemType=ProblemType;
- selectedColumnsInfoArray: ColumnInfo[] = [];
- selectedNotNullColumnsArray: string[] = [];
-
- tempTestSetDistribution = 90;
-
- constructor(private modelsService: ModelsService, private experimentsService: ExperimentsService) {
- }
-
- ngOnInit(): void {
- }
-
- updateDataset(dataset: Dataset) {
- this.selectedDataset = dataset;
- this.selectedColumnsInfoArray = this.selectedDataset.columnInfo;
- this.selectedNotNullColumnsArray = [];
- this.experiment.outputColumn = this.selectedDataset.columnInfo[this.selectedDataset.columnInfo.length - 1].columnName;
-
- this.resetColumnEncodings();
- console.log(this.experiment.encodings);
- }
-
- resetColumnEncodings() {
- this.experiment.encodings = [];
- for (let i = 0; i < this.selectedColumnsInfoArray.length; i++) {
- this.experiment.encodings.push(new ColumnEncoding(this.selectedColumnsInfoArray[i].columnName, Encoding.Label));
- }
- }
-
- getInputById(id: string): HTMLInputElement {
- return document.getElementById(id) as HTMLInputElement;
- }
-
- arrayColumn = (arr: any[][], n: number) => [...this.dropEmptyString(new Set(arr.map(x => x[n])))];
-
- dropEmptyString(set: Set<any>): Set<string> {
- if (set.has(""))
- set.delete("");
- if (set.has(null))
- set.delete(null);
- if (set.has(undefined))
- set.delete(undefined);
- return set;
- }
-
- emptyFillTextInput(colName: string) {
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = "";
- }
-
- checkFillColRadio(colName: string) {
- (<HTMLInputElement>document.getElementById("fillCol_" + colName)).checked = true;
- }
-
- checkedColumnsChanged(checkedColumnInfo: ColumnInfo, buttonType: number) { //0-input,1-output
- let col = this.selectedColumnsInfoArray.find(x => x.columnName == checkedColumnInfo.columnName);
- if (buttonType == 0) { //inputCol
- if (col == undefined)
- this.selectedColumnsInfoArray.push(checkedColumnInfo);
- else
- this.selectedColumnsInfoArray = this.selectedColumnsInfoArray.filter(x => x.columnName != checkedColumnInfo.columnName);
- }
- else { //outputCol
- if (col == undefined) //ako je vec cekiran neki output, samo dodaj sad ovaj, a taj output postaje input i ostaje u nizu
- this.selectedColumnsInfoArray.push(checkedColumnInfo);
- }
- //console.log(this.selectedColumnsInfoArray);
- }
-
- replace(event: Event, column: ColumnInfo) {
- let option = (<HTMLInputElement>event.target).value;
-
- const input = (<HTMLInputElement>document.getElementById("fillText_" + column.columnName));
- if (column.isNumber) {
- switch (option) {
- case ReplaceWith.Max:
- input.value = "" + column.max;
- break;
- case ReplaceWith.Min:
- input.value = "" + column.min;
- break;
- case ReplaceWith.Mean:
- input.value = "" + column.mean;
- break;
- case ReplaceWith.Median:
- input.value = "" + column.median;
- break;
- case ReplaceWith.None:
- break;
- }
- } else {
- input.value = option;
- }
- }
-
- getSelectedColumnsArrayWithoutNullVals(): string[] {
- let colNames: string[] = [];
-
- for (let i = 0; i < this.selectedColumnsInfoArray.length; i++) {
- let oneColInfo = this.selectedColumnsInfoArray[i];
- if (oneColInfo.numNulls == 0)
- colNames.push(oneColInfo.columnName);
- }
- return colNames;
- }
-
- getNullValuesReplacersArray(): NullValReplacer[] {
- let array: NullValReplacer[] = [];
-
- if (this.experiment.nullValues == NullValueOptions.Replace) {
-
- for (let i = 0; i < this.selectedColumnsInfoArray.length; i++) {
- let oneColInfo = this.selectedColumnsInfoArray[i];
-
- if (oneColInfo.numNulls > 0) { //ako kolona nema null vrednosti, ne dodajemo je u niz
- if ((<HTMLInputElement>document.getElementById("delCol_" + oneColInfo.columnName)).checked) {
- array.push({
- column: oneColInfo.columnName,
- option: NullValueOptions.DeleteColumns,
- value: ""
- });
- }
- else if ((<HTMLInputElement>document.getElementById("delRows_" + oneColInfo.columnName)).checked) {
- array.push({
- column: oneColInfo.columnName,
- option: NullValueOptions.DeleteRows,
- value: ""
- });
- }
- else if (((<HTMLInputElement>document.getElementById("fillCol_" + oneColInfo.columnName)).checked)) {
- array.push({
- column: oneColInfo.columnName,
- option: NullValueOptions.Replace,
- value: (<HTMLInputElement>document.getElementById("fillText_" + oneColInfo.columnName)).value
- });
- }
- }
- }
- }
- return array;
- }
-
- saveExperiment() {
- if (this.selectedDataset == undefined) {
- Shared.openDialog("Greška", "Izvor podataka nije izabran!");
- return;
- }
- if (this.experiment.outputColumn == '') {
- Shared.openDialog("Greška", "Molimo Vas da izaberete izlaznu kolonu.");
- return;
- }
- if (this.selectedColumnsInfoArray.length <= 1) { //jer izlazna je izabrana
- Shared.openDialog("Greška", "Molimo Vas da izaberete ulazne kolone.");
- return;
- }
-
- this.experiment._id = '';
- this.experiment.uploaderId = '';
- this.experiment.datasetId = this.selectedDataset._id;
-
- let pom = this.selectedColumnsInfoArray.filter(x => x.columnName != this.experiment.outputColumn);
- for (let i = 0; i < pom.length; i++)
- this.experiment.inputColumns.push(pom[i].columnName);
-
- this.selectedColumnsInfoArray = this.selectedColumnsInfoArray.filter(x => x.numNulls > 0); //obavezno
- this.experiment.nullValuesReplacers = this.getNullValuesReplacersArray();
-
- this.experiment.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10;
-
- console.log("Eksperiment:", this.experiment);
-
- this.experimentsService.addExperiment(this.experiment).subscribe((response) => {
- this.experiment = response;
-
- this.selectedColumnsInfoArray = [];
- this.selectedNotNullColumnsArray = [];
- this.experiment.encodings = [];
-
- Shared.openDialog("Obaveštenje", "Eksperiment je uspešno kreiran.");
- }, (error) => {
- if (error.error == "Experiment with this name exists") {
- Shared.openDialog("Greška", "Eksperiment sa unetim nazivom već postoji u Vašoj kolekciji. Unesite neki drugi naziv.");
- }
- });
- }
-
- countSelectedNullCols(): number {
- let counter: number = 0;
-
- for (let i = 0; i < this.selectedColumnsInfoArray.length; i++) {
- let oneColInfo = this.selectedColumnsInfoArray[i];
- if (oneColInfo.numNulls > 0)
- ++counter;
- }
- return counter;
- }
-}
diff --git a/frontend/src/app/training/training.component.html b/frontend/src/app/training/training.component.html
deleted file mode 100644
index 672e75fb..00000000
--- a/frontend/src/app/training/training.component.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<div id="header">
- <h1>Trenirajte veštačku neuronsku mrežu</h1>
-</div>
-<div id="wrapper" class="mb-4">
- <div id="container" class="container p-5 row" style="background-color: white; min-height: 100%;">
- <div class="col"></div>
-
- <div class="col-10">
-
- <h2>1. Izaberite eksperiment iz kolekcije</h2>
- <div class="px-5 mt-5 mb-3">
- <input type="text" class="form-control" placeholder="Pretraga"
- [(ngModel)]="term">
- </div>
- <div class="overflow-auto px-5" style="max-height: 500px;">
- <ul class="list-group">
- <li class="list-group-item p-3" *ngFor="let experiment of myExperiments|filter:term"
- [ngClass]="{'selectedExperimentClass': this.selectedExperiment == experiment}">
- <app-item-experiment [experiment]="experiment"
- (click)="selectThisExperiment(experiment);"></app-item-experiment>
- </li>
- </ul>
- </div>
-
- <h2 class="mt-5 mb-2">2. Izaberite model</h2>
- <app-model-load (selectedModelChangeEvent)="selectModel($event)" [forExperiment]="selectedExperiment"></app-model-load>
-
- <h2 class="my-5">3. Treniranje modela</h2>
-
- <div class="d-flex flex-row justify-content-center align-items-center my-3">
- <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="trainModel();">Treniraj
- model</button>
- </div>
-
- <h2 class="mt-5">Rezultati treniranja</h2>
- <div class="m-3" *ngIf="trainingResult">
- <h2 class="my-2">Rezultati treniranja:</h2>
- <p>
- {{trainingResult}}
- </p>
- </div>
- </div>
-
- <div class="col"></div>
- </div>
-</div> \ No newline at end of file