123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- // Create some graphs/plots
- //
- // 1. Use log-file to create graph of fitness against time
- // 2. Use similarities to create a heat map of the different models
- // 3. Use multi-dimensional scaling to generate a 2D representation of models
- // - plot this with optional clustering
- //
- // Requires following files on classpath:
- // 1. commons-csv-1.9.0.jar - https://repo1.maven.org/maven2/org/apache/commons/commons-csv/1.9.0/commons-csv-1.9.0.jar
- // 2. commons-math3-3.6.1.jar - https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
- // 3. mdsj.jar - https://www.inf.uni-konstanz.de/exalgo/software/mdsj/mdsj.jar
- // 4. xchart-3.8.2.jar - https://repo1.maven.org/maven2/org/knowm/xchart/xchart/3.8.2/xchart-3.8.2.jar
- //
- // e.g. on Windows, call with:
- // > java -cp commons-csv-1.9.0.jar;commons-math3-3.6.1.jar;mdsj.jar;xchart-3.8.2.jar Tutorial4Visualisations.java log-dmts.csv dmts-models.dat
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.io.IOException;
- import java.io.Reader;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Optional;
- import mdsj.MDSJ;
- import org.apache.commons.csv.CSVFormat;
- import org.apache.commons.csv.CSVRecord;
- import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
- import org.apache.commons.math3.ml.clustering.Clusterable;
- import org.knowm.xchart.SwingWrapper;
- import org.knowm.xchart.HeatMapChart;
- import org.knowm.xchart.HeatMapChartBuilder;
- import org.knowm.xchart.HeatMapSeries;
- import org.knowm.xchart.XYChart;
- import org.knowm.xchart.XYChartBuilder;
- import org.knowm.xchart.XYSeries;
- import org.knowm.xchart.style.colors.XChartSeriesColors;
- import org.knowm.xchart.style.markers.SeriesMarkers;
- public class Tutorial4Visualisations {
- public static void main (String[] args) {
- if (args.length == 2) {
- var logFile = Path.of(args[0]);
- var similarityFile = Path.of(args[1]);
- fitnessGraph(logFile);
- heatmapGraph(similarityFile);
- modelSimilarityGraph(similarityFile, 3);
- } else {
- System.out.println("Call with: log-file-name.csv similarity-file-name.dat");
- }
- }
- static void fitnessGraph(Path filepath) {
- try (Reader in = Files.newBufferedReader (filepath)) {
- // read in data
- List<LogFileEntry> data = CSVFormat.RFC4180.parse(in).stream()
- .map(LogFileEntry::fromCSVRecord)
- .flatMap(Optional::stream)
- .toList();
- // plot chart
- XYChart chart = new XYChartBuilder()
- .width(800)
- .height(600)
- .title("Fitness Against Generation: " + filepath.getFileName())
- .xAxisTitle("Generation")
- .yAxisTitle("Fitness")
- .build();
- chart.getStyler().setXAxisTickMarkSpacingHint(100);
- var xAxis = data.stream()
- .map(LogFileEntry::generation)
- .toList();
- var fitnessOverall = data.stream()
- .map(LogFileEntry::fitnessOverall)
- .toList();
- var fitnessAccuracy = data.stream()
- .map(LogFileEntry::fitnessAccuracy)
- .toList();
- var fitnessResponseTime = data.stream()
- .map(LogFileEntry::fitnessResponseTime)
- .toList();
- var fitnessProgramSize = data.stream()
- .map(LogFileEntry::fitnessProgramSize)
- .toList();
- XYSeries series = chart.addSeries("Fitness", xAxis, fitnessOverall);
- series.setLineColor(XChartSeriesColors.BLACK);
- series.setMarker(SeriesMarkers.NONE);
- series = chart.addSeries("Accuracy", xAxis, fitnessAccuracy);
- series.setLineColor(XChartSeriesColors.BLUE);
- series.setMarker(SeriesMarkers.NONE);
- series = chart.addSeries("Response Time", xAxis, fitnessResponseTime);
- series.setLineColor(XChartSeriesColors.RED);
- series.setMarker(SeriesMarkers.NONE);
- series = chart.addSeries("Program Size", xAxis, fitnessProgramSize);
- series.setLineColor(XChartSeriesColors.GREEN);
- series.setMarker(SeriesMarkers.NONE);
- new SwingWrapper<XYChart>(chart).displayChart();
- } catch (IOException ioe) {
- System.out.println("Exception: " + ioe);
- System.exit(-1);
- }
- }
- static void heatmapGraph (Path filepath) {
- var data = new ModelSimilarities (filepath);
- // plot chart
- HeatMapChart chart = new HeatMapChartBuilder()
- .width(800)
- .height(600)
- .title("Model Similarity: " + filepath.getFileName())
- .xAxisTitle("Individual")
- .yAxisTitle("Individual")
- .build();
- HeatMapSeries series = chart.addSeries("Similarities", data.xData, data.yData, data.similarities);
- new SwingWrapper<HeatMapChart>(chart).displayChart();
- }
- static void modelSimilarityGraph (Path filepath, int numClusters) {
- var data = new ModelSimilarities (filepath);
- var model = new KMeansPlusPlusClusterer<ModelSimilarities.Coord>(numClusters);
- var clusters = model.cluster (data.multiDimensionalScaling ());
- XYChart chart = new XYChartBuilder()
- .width(800)
- .height(600)
- .title("Model Similarity Visualisation: " + filepath.getFileName())
- .xAxisTitle("x")
- .yAxisTitle("y")
- .build();
- chart.getStyler().setDefaultSeriesRenderStyle(XYSeries.XYSeriesRenderStyle.Scatter);
- chart.getStyler().setLegendVisible(false);
- chart.getStyler().setMarkerSize(16);
- for (int c = 0; c < clusters.size (); c += 1) {
- var cluster = clusters.get (c);
- var xData = new double[cluster.getPoints().size ()];
- var yData = new double[cluster.getPoints().size ()];
- for (int i = 0; i < cluster.getPoints().size (); i += 1) {
- xData[i] = cluster.getPoints().get(i).x ();
- yData[i] = cluster.getPoints().get(i).y ();
- }
- chart.addSeries("Model Coordinate: " + c, xData, yData);
- }
- new SwingWrapper<XYChart>(chart).displayChart();
- }
- }
- record LogFileEntry(
- int generation,
- double fitnessOverall,
- double accuracy,
- double fitnessAccuracy,
- double responseTime,
- double fitnessResponseTime,
- double programSize,
- double fitnessProgramSize,
- double phase
- ) {
- static Optional<LogFileEntry> fromCSVRecord (CSVRecord record) {
- if (record.size() == 9) { // ensure we have enough parts
- try {
- int generation = Integer.parseInt(record.get(0));
- double fitnessOverall = Double.parseDouble(record.get(1));
- double accuracy = Double.parseDouble(record.get(2));
- double fitnessAccuracy = Double.parseDouble(record.get(3));
- double responseTime = Double.parseDouble(record.get(4));
- double fitnessResponseTime = Double.parseDouble(record.get(5));
- double programSize = Double.parseDouble(record.get(6));
- double fitnessProgramSize = Double.parseDouble(record.get(7));
- double phase = Double.parseDouble(record.get(8));
- return Optional.of(new LogFileEntry(
- generation,
- fitnessOverall,
- accuracy,
- fitnessAccuracy,
- responseTime,
- fitnessResponseTime,
- programSize,
- fitnessProgramSize,
- phase
- ));
- } catch (NumberFormatException e) {
- System.out.println("Exception: " + e);
- }
- }
- return Optional.empty();
- }
- }
- class ModelSimilarities {
- int[] xData;
- int[] yData;
- int[][] similarities;
- double[][] dissimilarities;
- ModelSimilarities (Path filepath) {
- try (Reader in = Files.newBufferedReader (filepath)) {
- // read in data
- List<ModelSimilarityEntry> data = CSVFormat.Builder
- .create(CSVFormat.RFC4180)
- .setDelimiter(' ')
- .build()
- .parse(in).stream()
- .map(ModelSimilarityEntry::fromCSVRecord)
- .flatMap(Optional::stream)
- .toList();
- xData = data.stream()
- .map(ModelSimilarityEntry::modelX)
- .distinct()
- .sorted()
- .mapToInt(i->i)
- .toArray();
- yData = data.stream()
- .map(ModelSimilarityEntry::modelY)
- .distinct()
- .sorted()
- .mapToInt(i->i)
- .toArray();
- similarities = new int[xData.length][yData.length];
- dissimilarities = new double[xData.length][yData.length];
- for (var entry : data) {
- similarities[entry.modelX()][entry.modelY()] = (int)Math.round(100 * entry.similarity());
- dissimilarities[entry.modelX()][entry.modelY()] = 1.0 - entry.similarity();
- }
- } catch (IOException ioe) {
- System.out.println("Model Similarities exception: " + ioe);
- System.exit(-1);
- }
- }
- List<Coord> multiDimensionalScaling () {
- var coords = MDSJ.classicalScaling(dissimilarities);
- var result = new ArrayList<Coord> ();
- for (int i = 0; i < coords[0].length; i += 1) {
- result.add (new Coord(coords[0][i], coords[1][i], new double[]{coords[0][i], coords[1][i]}));
- }
- return result;
- }
- record Coord(
- double x,
- double y,
- double[] point
- ) implements Clusterable {
- public double[] getPoint () {
- return point;
- }
- }
- record ModelSimilarityEntry(
- int modelX,
- int modelY,
- double similarity
- ) {
- static Optional<ModelSimilarityEntry> fromCSVRecord (CSVRecord record) {
- if (record.size() == 3) { // ensure we have enough parts
- try {
- int modelX = Integer.parseInt(record.get(0));
- int modelY = Integer.parseInt(record.get(1));
- double similarity = Double.parseDouble(record.get(2));
- return Optional.of(new ModelSimilarityEntry(
- modelX,
- modelY,
- similarity
- ));
- } catch (NumberFormatException e) {
- System.out.println("Exception: " + e);
- }
- }
- return Optional.empty();
- }
- }
- }
|