Skip to content
Snippets Groups Projects
Commit 67df57f4 authored by Hugo Debuyser's avatar Hugo Debuyser
Browse files

Merge remote-tracking branch 'origin/master' into hugodebuyser

parents c11af374 603ecc1a
No related branches found
No related tags found
No related merge requests found
Showing
with 469 additions and 91 deletions
......@@ -6,37 +6,55 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.stage.*?>
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/17.0.12" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.MainStageController">
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/17.0.12" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.DataStageController">
<scene>
<Scene>
<AnchorPane prefHeight="363.0" prefWidth="692.0">
<AnchorPane prefHeight="487.0" prefWidth="692.0">
<children>
<VBox prefHeight="363.0" prefWidth="691.0">
<VBox prefHeight="488.0" prefWidth="691.0">
<children>
<HBox prefHeight="356.0" prefWidth="691.0">
<HBox alignment="TOP_CENTER" prefHeight="356.0" prefWidth="691.0" spacing="5.0">
<children>
<Region prefHeight="338.0" prefWidth="65.0" />
<ScatterChart prefHeight="342.0" prefWidth="609.0">
<xAxis>
<CategoryAxis fx:id="absAxeView" prefHeight="21.0" prefWidth="498.0" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="ordAxeView" side="LEFT" />
</yAxis>
</ScatterChart>
<Button fx:id="settingsView" mnemonicParsing="false">
<graphic>
<ImageView fitHeight="100.0" fitWidth="30.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@gear.png" />
</image></ImageView>
</graphic>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<Region prefHeight="338.0" prefWidth="65.0" />
<ScatterChart fx:id="scatterChart" prefHeight="342.0" prefWidth="609.0">
<xAxis>
<NumberAxis fx:id="absAxe" prefHeight="21.0" prefWidth="498.0" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="ordAxe" side="LEFT" />
</yAxis>
</ScatterChart>
<Label fx:id="AxesSelected" alignment="CENTER" layoutX="175.0" layoutY="152.0" prefHeight="38.0" prefWidth="259.0">
<font>
<Font size="21.0" />
</font></Label>
</children>
<HBox.margin>
<Insets right="10.0" top="30.0" />
<Insets left="10.0" />
</HBox.margin>
</Button>
</AnchorPane>
<Button fx:id="settingsView" mnemonicParsing="false" onAction="#openAxesSetting">
<graphic>
<ImageView fitHeight="100.0" fitWidth="30.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@gear.png" />
</image>
</ImageView>
</graphic>
<HBox.margin>
<Insets top="40.0" />
</HBox.margin>
</Button>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="169.0" prefWidth="691.0" spacing="50.0">
<children>
<Button fx:id="classifyData" disable="true" mnemonicParsing="false" onAction="#classifyDatas" prefHeight="26.0" prefWidth="157.0" text="Classifier les données" />
</children>
</HBox>
</children>
......
......@@ -9,7 +9,7 @@
<?import javafx.scene.text.*?>
<?import javafx.stage.*?>
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/17.0.12" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.MainStageController">
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.MainStageController">
<scene>
<Scene>
<AnchorPane prefHeight="487.0" prefWidth="692.0">
......@@ -52,13 +52,18 @@
</Button>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="169.0" prefWidth="691.0" spacing="50.0">
<VBox alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0">
<children>
<Button fx:id="loadData" mnemonicParsing="false" onAction="#openLoadData" prefHeight="27.0" prefWidth="185.0" text="Charger un jeu de données" />
<Button fx:id="addData" mnemonicParsing="false" onAction="#openAddData" prefHeight="26.0" prefWidth="141.0" text="Ajouter une donnée" />
<Button fx:id="classifyData" disable="true" mnemonicParsing="false" onAction="#classifyDatas" prefHeight="26.0" prefWidth="157.0" text="Classifier les données" />
<HBox alignment="CENTER" prefHeight="85.0" prefWidth="691.0" spacing="50.0">
<children>
<Button fx:id="loadData" mnemonicParsing="false" onAction="#openLoadData" prefHeight="27.0" prefWidth="185.0" text="Charger un jeu de données" />
<Button fx:id="addData" mnemonicParsing="false" onAction="#openAddData" prefHeight="26.0" prefWidth="141.0" text="Ajouter une donnée" />
<Button fx:id="classifyData" disable="true" mnemonicParsing="false" onAction="#classifyDatas" prefHeight="26.0" prefWidth="157.0" text="Classifier les données" />
</children>
</HBox>
<Button alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#openDataView" text="Ouvrir une autre vue" />
</children>
</HBox>
</VBox>
</children>
</VBox>
</children></AnchorPane>
......
......@@ -2,6 +2,7 @@ package fr.univlille.sae.classification.controller;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.model.Iris;
import fr.univlille.sae.classification.view.DataVisualizationView;
import fr.univlille.sae.classification.view.MainStageView;
import javafx.fxml.FXML;
import javafx.scene.control.*;
......
package fr.univlille.sae.classification.controller;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.view.MainStageView;
import fr.univlille.sae.classification.view.DataVisualizationView;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
......@@ -21,31 +21,31 @@ public class AxesSettingsController{
@FXML
Button confirmAxes;
MainStageView mainStageView;
DataVisualizationView dataVisualizationView;
public void setSelectOrd(String[] fields){
selectOrd.getItems().clear();
selectOrd.getItems().addAll(fields);
selectOrd.setValue(mainStageView.getActualY());
selectOrd.setValue(dataVisualizationView.getActualY());
}
public void setSelectAbs(String[] fields){
selectAbs.getItems().clear();
selectAbs.getItems().addAll(fields);
selectAbs.setValue(mainStageView.getActualX());
selectAbs.setValue(dataVisualizationView.getActualX());
}
public void setMainStageView(MainStageView mainStageView) {
this.mainStageView = mainStageView;
public void setdataVisualizationView(DataVisualizationView dataVisualizationView) {
this.dataVisualizationView = dataVisualizationView;
}
public void validate(){
mainStageView.setActualX(selectAbs.getValue().toString());
mainStageView.setActualY(selectOrd.getValue().toString());
mainStageView.getController().getScatterChart().getXAxis().setLabel(mainStageView.getActualX());
mainStageView.getController().getScatterChart().getYAxis().setLabel(mainStageView.getActualY());
dataVisualizationView.setActualX(selectAbs.getValue().toString());
dataVisualizationView.setActualY(selectOrd.getValue().toString());
dataVisualizationView.getScatterChart().getXAxis().setLabel(dataVisualizationView.getActualX());
dataVisualizationView.getScatterChart().getYAxis().setLabel(dataVisualizationView.getActualY());
mainStageView.update(ClassificationModel.getClassificationModel());
dataVisualizationView.reload();
stage.close();
}
}
package fr.univlille.sae.classification.controller;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.view.*;
import javafx.fxml.FXML;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import java.io.IOException;
public class DataStageController {
@FXML
Stage stage;
@FXML
NumberAxis absAxe;
@FXML
NumberAxis ordAxe;
@FXML
Button settings;
@FXML
Button loadData;
@FXML
Button classifyData;
@FXML
ScatterChart scatterChart;
@FXML
Label AxesSelected;
Stage loadStage;
private DataStageView dataStageView;
/**
* Ouvre l'interface de chargement des données.
* @throws IOException
*/
public void openLoadData() throws IOException {
LoadDataView loadDataView = new LoadDataView(ClassificationModel.getClassificationModel(), stage);
loadDataView.show();
}
public void openAxesSetting()throws IOException {
AxesSettingsView axesSettingsView = new AxesSettingsView(ClassificationModel.getClassificationModel(), stage, dataStageView);
axesSettingsView.show();
}
public void setDataStageView (DataStageView dataStageView) {
this.dataStageView = dataStageView;
}
public void classifyDatas() {
ClassificationModel.getClassificationModel().classifierDonnees();
classifyData.setDisable(true);
}
public ScatterChart getScatterChart() {
return this.scatterChart;
}
public void setAxesSelected(String texte) {
this.AxesSelected.setText(texte);
}
public Button getClassifyData() {
return this.classifyData;
}
}
package fr.univlille.sae.classification.controller;
import javafx.fxml.FXML;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class DataViewStage {
@FXML
Stage stage;
@FXML
CategoryAxis absAxe;
@FXML
NumberAxis ordAxe;
@FXML
Button settings;
}
package fr.univlille.sae.classification.controller;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.view.AxesSettingsView;
import fr.univlille.sae.classification.view.LoadDataView;
import fr.univlille.sae.classification.view.AddDataView;
import fr.univlille.sae.classification.view.MainStageView;
import fr.univlille.sae.classification.view.*;
import javafx.fxml.FXML;
import javafx.scene.chart.*;
......@@ -59,6 +56,11 @@ public class MainStageController {
loadDataView.show();
}
public void openDataView() throws IOException {
DataStageView dataStageView = new DataStageView(ClassificationModel.getClassificationModel());
dataStageView.show();
}
public void openAxesSetting()throws IOException {
AxesSettingsView axesSettingsView = new AxesSettingsView(ClassificationModel.getClassificationModel(), stage, mainStageView);
axesSettingsView.show();
......
......@@ -24,8 +24,6 @@ public class AddDataView {
this.mainStageView = mainStageView;
}
public void show() throws IOException {
FXMLLoader loader = new FXMLLoader();
......
package fr.univlille.sae.classification.view;
import fr.univlille.sae.classification.controller.AxesSettingsController;
import fr.univlille.sae.classification.controller.DataStageController;
import fr.univlille.sae.classification.controller.MainStageController;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.model.LoadableData;
......@@ -9,6 +10,7 @@ import javafx.scene.control.Alert;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javax.xml.crypto.Data;
import java.io.File;
import java.io.IOException;
import java.net.URL;
......@@ -18,12 +20,12 @@ public class AxesSettingsView {
private ClassificationModel model;
private Stage owner;
private MainStageView mainStageView;
private DataVisualizationView dataVisualizationView;
public AxesSettingsView(ClassificationModel model, Stage owner, MainStageView mainStageView){
public AxesSettingsView(ClassificationModel model, Stage owner, DataVisualizationView dataVisualizationView){
this.model = model;
this.owner = owner;
this.mainStageView = mainStageView;
this.dataVisualizationView = dataVisualizationView;
}
public void show() throws IOException {
......@@ -44,7 +46,7 @@ public class AxesSettingsView {
root.setTitle("Configuration des axes");
AxesSettingsController controller = loader.getController();
controller.setMainStageView(mainStageView);
controller.setdataVisualizationView(dataVisualizationView);
if(model.getDatas().isEmpty()) {
Alert alert = new Alert(Alert.AlertType.WARNING);
......
package fr.univlille.sae.classification.view;
import fr.univlille.sae.classification.controller.DataStageController;
import fr.univlille.sae.classification.controller.MainStageController;
import fr.univlille.sae.classification.model.ClassificationModel;
import fr.univlille.sae.classification.model.DataType;
import fr.univlille.sae.classification.model.Iris;
import fr.univlille.sae.classification.model.LoadableData;
import fr.univlille.sae.classification.utils.Observable;
import fr.univlille.sae.classification.utils.Observer;
import javafx.fxml.FXMLLoader;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class DataStageView extends DataVisualizationView implements Observer {
private ClassificationModel model;
private DataStageController controller;
private Stage root;
public DataStageView(ClassificationModel model) {
this.model = model;
model.attach(this);
}
public void show() throws IOException {
FXMLLoader loader = new FXMLLoader();
URL fxmlFileUrl = new File(System.getProperty("user.dir") + File.separator + "res" + File.separator + "stages" + File.separator + "data-view-stage.fxml").toURI().toURL();
if (fxmlFileUrl == null) {
System.out.println("Impossible de charger le fichier fxml");
System.exit(-1);
}
loader.setLocation(fxmlFileUrl);
root = loader.load();
root.setResizable(false);
root.setTitle("SAE3.3 - Logiciel de classification");
root.show();
loader.getController();
controller = loader.getController();
controller.setDataStageView(this);
scatterChart = controller.getScatterChart();
controller.setAxesSelected("Aucun fichier sélectionné");
if (!model.getDatas().isEmpty()) {
update(model);
}
}
@Override
public void update(Observable observable) {
if(scatterChart == null) throw new IllegalStateException();
if(!(observable instanceof ClassificationModel)) throw new IllegalStateException();
//on vide le nuage pour s'assurer que celui-ci est bien vide
scatterChart.getData().clear();
XYChart.Series series1 = new XYChart.Series();
series1.setName("Iris");
//Jalon 1: on verifie que le type de donnée est bien IRIS
if(model.getType() == DataType.IRIS) {
if(actualX==null && actualY==null){
controller.setAxesSelected("Aucuns axes sélectionnés");
}
else{
controller.setAxesSelected("");
// On ajoute la serie au nuage
scatterChart.getData().add(series1);
//On recupere les données du model
List<LoadableData> points = new ArrayList<>(model.getDatas());
points.addAll(model.getDataToClass());
// on ajoute chaque point a la serie
for(LoadableData i : points) {
Iris iris = (Iris)i;
XYChart.Data<Double, Double> dataPoint = new XYChart.Data<>(iris.getDataType(actualX),
iris.getDataType(actualY));
dataPoint.setNode(getCircle(iris));
series1.getData().add(dataPoint);
}
}
}
}
private Circle getCircle(Iris iris) {
Circle circle = new Circle(5);
circle.setFill(iris.getColor());
circle.setOnMouseClicked(e -> {
ContextMenu contextMenu = new ContextMenu();
for(String attributes : iris.getAttributesName()) {
contextMenu.getItems().add(new MenuItem(attributes + " : " + iris.getDataType(attributes)));
}
contextMenu.show(root, e.getScreenX(), e.getScreenY());
});
return circle;
}
@Override
public void update(Observable observable, Object data) {
if(scatterChart == null) throw new IllegalStateException();
if(!(observable instanceof ClassificationModel)) throw new IllegalStateException();
if(data instanceof Iris) {
Iris iris = (Iris) data;
if(actualX == null || actualY == null) {
controller.setAxesSelected("Aucuns axes sélectionnés");
return;
}
XYChart.Data<Double, Double> dataPoint = new XYChart.Data<>(
iris.getDataType(actualX),
iris.getDataType(actualY)
);
dataPoint.setNode(getCircle(iris));
if (!scatterChart.getData().isEmpty()) {
XYChart.Series series = (XYChart.Series) scatterChart.getData().get(0);
series.getData().add(dataPoint);
}
}
}
public DataStageController getController() {
return controller;
}
@Override
public void reload() {
this.update(ClassificationModel.getClassificationModel());
}
}
package fr.univlille.sae.classification.view;
import javafx.scene.chart.ScatterChart;
public abstract class DataVisualizationView {
protected DataVisualizationView() {}
protected String actualX;
protected String actualY;
protected ScatterChart scatterChart;
public String getActualX() {
return actualX;
}
public void setActualX(String actualX) {
this.actualX = actualX;
}
public String getActualY() {
return actualY;
}
public void setActualY(String actualY) {
this.actualY = actualY;
}
public ScatterChart getScatterChart() {
return this.scatterChart;
}
public abstract void reload();
}
......@@ -26,14 +26,11 @@ import java.io.IOException;
import java.net.URL;
import java.util.*;
public class MainStageView implements Observer {
public class MainStageView extends DataVisualizationView implements Observer {
private ClassificationModel model;
private ScatterChart scatterChart;
private MainStageController controller;
private String actualX;
private String actualY;
private Stage root;
public MainStageView(ClassificationModel model) {
......@@ -154,24 +151,12 @@ public class MainStageView implements Observer {
}
}
public void setActualX(String actualX) {
this.actualX = actualX;
}
public void setActualY(String actualY) {
this.actualY = actualY;
}
public String getActualX() {
return actualX;
}
public String getActualY() {
return actualY;
}
public MainStageController getController() {
return controller;
}
@Override
public void reload() {
this.update(ClassificationModel.getClassificationModel());
}
}
package fr.univlille.sae.classification.model;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class ClassificationModelTest {
private ClassificationModel model;
@BeforeEach
void setUp() {
model = ClassificationModel.getClassificationModel();
}
@Test
void testSingletonInstance() {
ClassificationModel anotherModel = ClassificationModel.getClassificationModel();
assertSame(model, anotherModel);
}
@Test
void testAjouterDonnee() {
double[] coords = {5.1, 3.5, 1.4, 0.2};
model.ajouterDonnee(coords);
List<LoadableData> dataToClass = model.getDataToClass();
assertEquals(1, dataToClass.size());
assertNotNull(dataToClass.get(0).getClassification());
}
@Test
void testAjouterDonneeInsuffisante() {
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
model.ajouterDonnee(5.1);
});
assertEquals(null, exception.getMessage());
}
@Test
void testLoadData() throws IOException {
File csvTemp = File.createTempFile("test", ".csv");
String csvTest = "sepal_length,sepal_width,petal_length,petal_width,class\n" +
"5.1,3.5,1.4,0.2,Iris-setosa\n" +
"4.9,3.0,1.4,0.2,Iris-setosa\n";
Files.write(Paths.get(csvTemp.getAbsolutePath()), csvTest.getBytes());
model.loadData(csvTemp);
List<LoadableData> datas = model.getDatas();
assertEquals(2, datas.size());
csvTemp.delete();
}
@Test
void testClassifierDonnees() {
double[] coords1 = {5.1, 3.5, 1.4, 0.2};
double[] coords2 = {4.9, 3.0, 1.4, 0.2};
model.ajouterDonnee(coords1);
model.ajouterDonnee(coords2);
model.classifierDonnees();
assertEquals(0, model.getDataToClass().size());
}
@Test
void testSetType() {
model.setType(DataType.IRIS);
assertEquals(DataType.IRIS, model.getType());
}
}
package fr.univlille.sae.classification.model;
import javafx.scene.paint.Color;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class IrisTest {
Iris iris = new Iris(2.8, 3.0, 1.9, 4.1, "Setosa");
@Test
void getSepalWidth() {
assertEquals(3.0 , iris.getSepalWidth());
}
@Test
void getSepalLength() {
assertEquals(2.8, iris.getSepalLength());
}
@Test
void getPetalWidth() {
assertEquals(4.1, iris.getPetalWidth());
}
@Test
void getPetalLength() {
assertEquals(1.9, iris.getPetalLength());
}
@Test
void getDataType() {
assertEquals(3.0 , iris.getDataType("sepalWidth"));
assertEquals(2.8, iris.getDataType("sepalLength"));
assertEquals(4.1, iris.getDataType("petalWidth"));
assertEquals(1.9, iris.getDataType("petalLength"));
}
@Test
void getColor() {
assertEquals(Color.RED, iris.getColor());
}
@Test
void testToString() {
assertEquals("Iris{sepalLength=2.8, sepalWidth=3.0, petalLength=1.9, petalWidth=4.1}", iris.toString());
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment