package com.application.GUI; import com.application.DB.Constants; import com.application.DB.Settings; import com.application.GUI.PopUpWindows.NotificationPopUp; import com.application.Main; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import org.apache.commons.math3.distribution.TDistribution; import org.apache.commons.math3.exception.MathIllegalArgumentException; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; import org.apache.commons.math3.stat.regression.SimpleRegression; import org.jblas.DoubleMatrix; import org.jblas.Solve; import java.text.SimpleDateFormat; import java.util.*; import static com.application.Main.*; public class LineChartFunctionality { private static LineChart<String, Number> lineChart; private static XYChart.Series<String, Number> liveDataSeries; private static XYChart.Series<String, Number> regressionSeries; private static XYChart.Series<String, Number> regressionSeriesConfidenceInterval; private static CategoryAxis xAxis; private static NumberAxis yAxis; private static int dataPointsXAxis = 0; private static int dataPointsYAxis = 0; private static Map<String, Number> liveData; private static ArrayList<XYChart.Series<String, Number>> previousData; private static boolean printRegression; private static boolean printRegressionConfidenceInterval; private static boolean printLiveData; private static boolean printPreviousData; public LineChartFunctionality() { xAxis = new CategoryAxis(); yAxis = new NumberAxis(); lineChart = new LineChart<>(xAxis, yAxis); lineChart.setTitle("Drying Processes"); lineChart.setAnimated(false); xAxis.setLabel("Data Points"); xAxis.setAnimated(false); yAxis.setLabel("Kwh"); yAxis.setAnimated(false); regressionSeries = new XYChart.Series<String, Number>(); regressionSeriesConfidenceInterval = new XYChart.Series<String, Number>(); liveDataSeries = new XYChart.Series<String, Number>(); previousData = new ArrayList<>(); printRegression = true; printRegressionConfidenceInterval = false; printLiveData = true; printPreviousData = true; } /** * Prints the graphs to the line chart * * Note: Something wrong when exceeding 8 series, think the next series choose a random series color */ public static void printGraphs() { getLineChart().getData().clear(); if(isPrintRegressionConfidenceInterval()){ updateLineChart(getRegressionSeriesConfidenceInterval()); getMenuViewRegressionShadow().setSelected(true); getRegressionConfidenceIntervalBox().setSelected(true); } else { updateLineChart(new XYChart.Series<>()); getMenuViewRegressionShadow().setSelected(false); getRegressionConfidenceIntervalBox().setSelected(false); } if(isPrintRegression()){ updateLineChart(getRegressionSeries()); getMenuViewRegression().setSelected(true); getRegressionBox().setSelected(true); } else { updateLineChart(new XYChart.Series<>()); getMenuViewRegression().setSelected(false); getRegressionBox().setSelected(false); } if(isPrintLiveData()){ updateLineChart(getLiveDataSeries()); getMenuViewLiveData().setSelected(true); getLiveDataBox().setSelected(true); } else { updateLineChart(new XYChart.Series<>()); getMenuViewLiveData().setSelected(false); getLiveDataBox().setSelected(false); } if(isPrintPreviousData()){ getPreviousBox().setSelected(true); getMenuViewPreviousData().setSelected(true); // If there are more than 5 series, adds 3 new empty series to keep the color scheme //int index = getLineChart().getData().size(); for (int i = 0; i < getPreviousData().size(); i++) { int index = getLineChart().getData().size(); //System.out.println(getPreviousData().size()); if (index % 8 == 0 ){ for (int j = 0; j < 3; j++) { updateLineChart(new XYChart.Series<>()); //index++; System.out.println("@@@@@@@"); } } updateLineChart(getPreviousData().get(i)); } } else { getPreviousBox().setSelected(false); getMenuViewPreviousData().setSelected(false); } } private static Map<Integer, ArrayList<Double>> statistics(Map<Integer, ArrayList<Double>> multiMap, boolean CIShadow){ //System.out.println("\n\nMultimap: \n"); for (Map.Entry<Integer, ArrayList<Double>> entry : multiMap.entrySet()) { //System.out.printf("\nIndex: \t%s\t\t\tkWh: \t%s\n", entry.getKey(), entry.getValue()); //System.out.println("entry: "+entry); //if(entry.getValue().size()>1){ SummaryStatistics stats = new SummaryStatistics(); for (double val : entry.getValue()) { stats.addValue(val); } //System.out.println("Stats: "+stats); // Calculate 95% confidence interval double ci = calcMeanCI(stats, Settings.CONFIDENCE_INTERVAL); //System.out.println(String.format("Mean: %f", stats.getMean())); double lower = stats.getMean() - ci; double upper = stats.getMean() + ci; //System.out.println(String.format("Confidence Interval "+ Settings.CONFIDENCE_INTERVAL*100+"%%: %f, %f", lower, upper)); // Deletes entries if they are out of bounds with the confidence interval entry.getValue().removeIf(value -> Double.compare(value, lower) < 0 || Double.compare(value, upper) > 0); if(CIShadow){ ArrayList<Double> lowerUpperBounds = new ArrayList<>(); lowerUpperBounds.add(lower); lowerUpperBounds.add(upper); multiMap.replace(entry.getKey(), lowerUpperBounds); } //} } return multiMap; } private static double calcMeanCI(SummaryStatistics stats, double level) { try { // Create T Distribution with N-1 degrees of freedom TDistribution tDist = new TDistribution(stats.getN() - 1); // Calculate critical value double critVal = tDist.inverseCumulativeProbability(1.0 - (1 - level) / 2); // Calculate confidence interval return critVal * stats.getStandardDeviation() / Math.sqrt(stats.getN()); } catch (MathIllegalArgumentException e) { return Double.NaN; } } public static LineChart<String, Number> loadSingleSeries(Map<Integer, Map<String, Number>> userInput) throws Exception { clearLineChart(); Map<Integer, ArrayList<Double>> multiMap = new HashMap<>(); for (Map.Entry<Integer, Map<String, Number>> entryKwh : userInput.entrySet()) { Map data = entryKwh.getValue(); //System.out.println(data.size()); XYChart.Series<String, Number> newSeries = new XYChart.Series<String, Number>(); int index = 0; for (Object entryData : data.entrySet()) { //System.out.println("data: \t"+entryData); String entryString = entryData.toString(); String[] arr = entryString.split("="); String date = arr[0]; Double kwhValue = Double.parseDouble(arr[1]); //System.out.printf("Date: \t%s\t\t\tkWh: \t%s\n",date,kwhValue); // Checks if the index already got an arraylist, if not one is created multiMap.computeIfAbsent(index, k -> new ArrayList<Double>()); multiMap.get(index).add(kwhValue); // Connect the data to a series newSeries.getData().add(new XYChart.Data<String, Number>(String.valueOf(index), kwhValue)); index++; } //allSeries.add(newSeries); //updateLineChart(newSeries); //lineChart.setOpacity(1); } //System.out.println("Series size: "+allSeries.size()); // Finds the end datapoint at the end of each graph int numberOfGraphs = 0; ArrayList<Double> dataArraylistXAxis = new ArrayList<>(); ArrayList<Double> dataArraylistYAxis = new ArrayList<>(); Map<Integer, ArrayList<Double>> endOfGraphPointsXAxis = new HashMap<>(); Map<Integer, ArrayList<Double>> endOfGraphPointsYAxis = new HashMap<>(); for (int i = 0; i < multiMap.size(); i++) { ArrayList<Double> list = multiMap.get(i); for (int j = 0; j < list.size(); j++) { if (numberOfGraphs < list.size()) { numberOfGraphs = list.size(); } if (list.size() < numberOfGraphs) { dataArraylistXAxis.add((double) i); dataArraylistYAxis.add(multiMap.get(i).get(j)); //System.out.println(tempList); numberOfGraphs = list.size(); } } } dataArraylistXAxis.add((double) multiMap.size()); dataArraylistYAxis.add(multiMap.get(multiMap.size()-1).get(0)); //System.out.println(dataArraylistYAxis); endOfGraphPointsXAxis.put(0,dataArraylistXAxis); endOfGraphPointsYAxis.put(0,dataArraylistYAxis); System.out.println(endOfGraphPointsXAxis); System.out.println(endOfGraphPointsYAxis); Map<Integer, ArrayList<Double>> endOfGraphPointsConfidenceXAxis = statistics(endOfGraphPointsXAxis,false); Map<Integer, ArrayList<Double>> endOfGraphPointsConfidenceYaxis = statistics(endOfGraphPointsYAxis,false); System.out.println("X-axis:"+ endOfGraphPointsConfidenceXAxis); System.out.println("X-axis size: "+ endOfGraphPointsConfidenceXAxis.size()); System.out.println("------------"); System.out.println("Y-axis:"+ endOfGraphPointsConfidenceYaxis); System.out.println("Y-axis size: "+ endOfGraphPointsConfidenceYaxis.size()); System.out.println("------------"); dataPointsXAxis = 0; for (Map.Entry<Integer, ArrayList<Double>> entry : endOfGraphPointsConfidenceXAxis.entrySet()) { System.out.println("Arraylist: "+ entry.getValue()); for (int i = 0; i < entry.getValue().size(); i++) { System.out.println("End of graphs: "+ entry.getValue().get(i)); dataPointsXAxis += entry.getValue().get(i); } } dataPointsXAxis = dataPointsXAxis /endOfGraphPointsConfidenceXAxis.get(0).size(); System.out.println("Datapoints: " + dataPointsXAxis); dataPointsYAxis = 0; for (Map.Entry<Integer, ArrayList<Double>> entry : endOfGraphPointsConfidenceYaxis.entrySet()) { System.out.println("Arraylist: "+ entry.getValue()); for (int i = 0; i < entry.getValue().size(); i++) { System.out.println("End of graphs: "+ entry.getValue().get(i)); dataPointsYAxis += entry.getValue().get(i); } } dataPointsYAxis = dataPointsYAxis /endOfGraphPointsConfidenceYaxis.get(0).size(); System.out.println("Datapoints Y-axis: " + dataPointsYAxis); // Stores the data from the confidence interval in a new map Map<Integer, ArrayList<Double>> confidenceIntervalData = statistics(multiMap,false); //getNonLinearRegression(confidenceIntervalData); // Checks the max size for the arraylists needed for the data array later int jMaxSize = 0; for (int i = 0; i < confidenceIntervalData.size(); i++) { if(confidenceIntervalData.get(i).size() > jMaxSize){ jMaxSize = confidenceIntervalData.get(i).size(); } } // Defines an array to be used for the regression double[][] data = new double[confidenceIntervalData.size()*jMaxSize][2]; int index = 0; //System.out.println(confidenceIntervalData); for (int i = 0; i < confidenceIntervalData.size(); i++) { ArrayList<Double> list = confidenceIntervalData.get(i); for (int j = 0; j < list.size(); j++) { data[index][0] = i; data[index][1] = list.get(j); index++; } } getRegressionSeriesConfidenceInterval().getData().clear(); Map<Integer, ArrayList<Double>> confidenceIntervalShadow = statistics(multiMap,true); for ( Map.Entry<Integer, ArrayList<Double>> entry : confidenceIntervalShadow.entrySet()) { for (int i = 0; i < entry.getValue().size(); i++) { Double doubleData = entry.getValue().get(i); getRegressionSeriesConfidenceInterval().getData().add(new XYChart.Data<String, Number>(String.valueOf(entry.getKey()), doubleData.intValue())); } } System.out.println(data.length); //System.out.println(data[12][1]); SimpleRegression simpleRegression = new SimpleRegression(); simpleRegression.addData(data); //simpleRegression.regress(); for (double[] datum : data) { //System.out.println(""); for (double v : datum) { //System.out.println("Data: "+v); } } //updateLineChart(liveDataSeries); //XYChart.Series<String, Number> regressionSeries = new XYChart.Series<String, Number>(); getRegressionSeries().getData().clear(); for (int i = 0; i <= getDataPointsXAxis(); i++) { // Connect the data to a series //System.out.println(simpleRegression.predict(i)); //regressionSeries.getData().add(new XYChart.Data<String, Number>(String.valueOf(i), simpleRegression.predict(i))); /* regressionSeries.getData().add(new XYChart.Data<String, Number>( String.valueOf(i), getNonLinearRegression( confidenceIntervalData, getDataPointsYAxis(), //simpleRegression.getIntercept(), simpleRegression.getSlope(), //simpleRegression.getIntercept() getDataPointsYAxis(), i, getDataPointsXAxis() ))); */ /* regressionSeries.getData().add(new XYChart.Data<String, Number>( String.valueOf(i), getCubicNonLinearRegression(confidenceIntervalData,i) )); */ getRegressionSeries().getData().add(new XYChart.Data<String, Number>( String.valueOf(i), getNonLinearRegression( confidenceIntervalData, Math.sqrt(Math.pow(simpleRegression.getIntercept(),2)), simpleRegression.getSlope(), i, getDataPointsXAxis() ))); } //updateLineChart(getRegressionSeries()); //lineChart.setOpacity(1); getPreviousData().clear(); for (Map.Entry<Integer, Map<String, Number>> entryKwh : userInput.entrySet()) { //System.out.println(data.size()); XYChart.Series<String, Number> newSeries = new XYChart.Series<String, Number>(); index = 0; for (Object entryData : entryKwh.getValue().entrySet()) { //System.out.println("data: \t"+entryData); String entryString = entryData.toString(); Double kwhValue = Double.parseDouble(entryString.split("=")[1]); // Connect the data to a series newSeries.getData().add(new XYChart.Data<String, Number>(String.valueOf(index), kwhValue)); index++; } addPreviousData(newSeries); //allSeries.add(newSeries); //updateLineChart(newSeries); //lineChart.setOpacity(1); } System.out.println("Get R: " + simpleRegression.getR()); System.out.println("Get getRSquare: " + simpleRegression.getRSquare()); System.out.println("Get getRegressionSumSquares: " + simpleRegression.getRegressionSumSquares()); System.out.println("Get N: " + simpleRegression.getN()); // and then you can predict the time at a given temperature value System.out.println("Predicted Time: " + simpleRegression.predict(35)); // You can also get the slope and intercept from your data System.out.println("Alpha! = " + simpleRegression.getSlope()); System.out.println("intercept = " + simpleRegression.getIntercept()); //simpleRegression.add getTimeLeft(0); printGraphs(); return getLineChart(); } public static void loadLiveData(Map<String, Number> userInput) throws Exception { // Clears any data already there getLiveDataSeries().getData().clear(); // Sets the livedata in series setLiveData(userInput); // Updates time left getTimeLeft(userInput.size()); for (Map.Entry<String, Number> entryKwh : userInput.entrySet()) { // Finds the index value int index = (int) (findDifference(Constants.START_TIME, entryKwh.getKey()) / 10); // Gets kwh value Double kwhValue = entryKwh.getValue().doubleValue(); // Connect the data to a series getLiveDataSeries().getData().add(new XYChart.Data<String, Number>(String.valueOf(index), kwhValue)); } } private static long findDifference(String start_date, String end_date) { // Defining a simple date format SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try{ // try to convert the string to Date datatype Date dateStart = dateFormat.parse(start_date); Date dateEnd = dateFormat.parse(end_date); // Finds the difference in millis long differenceMillis = dateEnd.getTime() - dateStart.getTime(); // Finds the difference in minutes return (differenceMillis / (1000 * 60 )) % 60; } catch (Exception e) { System.out.println(e.getMessage()); } return 0; } public static void getTimeLeft(int liveData){ int minutes = 0; int hours = 0; if(liveData == 0) { minutes = getDataPointsXAxis()*10; } else { minutes = (getDataPointsXAxis()/liveData)*10; } if(minutes > 60){ hours = minutes/60; Main.setTimeLeftText(hours + " h"); if(hours == 3){ NotificationPopUp.displayNotificationWindow("3 Hours Left!");} } else { if(minutes == 60){NotificationPopUp.displayNotificationWindow("1 Hours Left!");} Main.setTimeLeftText(minutes + " min"); } if(minutes == 0 && getDataPointsXAxis() != 0){ NotificationPopUp.displayNotificationWindow("Drying Process Finished!"); } } public static double getNonLinearRegression(Map<Integer, ArrayList<Double>> confidenceIntervalData, double y0, double alpha, double j, double n) { //return Math.exp(intercept+slope*i)/(1+Math.exp(intercept+slope*i)); double beta = 0.0; //double n = confidenceIntervalData.size(); for (Map.Entry<Integer, ArrayList<Double>> entry : confidenceIntervalData.entrySet()) { for (int i = 0; i < entry.getValue().size(); i++) { if(beta < entry.getValue().get(i)){ beta = entry.getValue().get(i); } } } beta = getDataPointsYAxis()+y0; //System.out.println("Beta: " +beta); //System.out.println("y0: "+y0); //System.out.println("maxYValue: " + maxYValue); //System.out.println("j*n: "+j/n); //double p_t = (((beta * y0))/(y0 +((beta- y0)*Math.exp(-alpha*j/n/(ADJUST_REGRESSION)))))-y0; //Beste til nå double p_t = (((beta * y0))/(y0 +((beta- y0)*Math.exp(-alpha*j/n/((alpha/10))))))-y0; //Beste til nå //double p_t = (((beta * y0))/(y0 +((beta- y0)*Math.exp(-alpha*(j-n)))))-y0; //Beste til nå /* System.out.println("---------------------------"); System.out.println("y0: " + y0); System.out.println("Alpha: " + alpha); System.out.println("Beta: " + beta); //System.out.println(p_t); */ return p_t; } /** * Third degree cubic non-linear regression * * n = * * sumT1 = * sumT2 = * sumT3 = * sumT4 = * * sumY = * sumYxT1= * sumYxT2 = * @param confidenceIntervalData Data to process * @return */ public static double getCubicNonLinearRegression(Map<Integer, ArrayList<Double>> confidenceIntervalData, int index){ double n = confidenceIntervalData.size(); //double n = getDataPointsYAxis(); //System.out.println(n); double sumT1 = 0; double sumT2 = 0; double sumT3 = 0; double sumT4 = 0; double sumY = 0; double sumYxT1 = 0; double sumYxT2 = 0; for (Map.Entry<Integer, ArrayList<Double>> entry : confidenceIntervalData.entrySet()) { sumT1 += entry.getKey(); sumT2 += Math.pow(entry.getKey(),2); sumT3 += Math.pow(entry.getKey(),3); sumT4 += Math.pow(entry.getKey(),4); for (int j = 0; j < entry.getValue().size(); j++) { sumY += entry.getValue().get(j); sumYxT1 += entry.getValue().get(j) * entry.getKey(); sumYxT2 += entry.getValue().get(j) * Math.pow(entry.getKey(), 2); } } /* for (Map.Entry<Integer, ArrayList<Double>> entry : confidenceIntervalData.entrySet()) { for (int j = 0; j < entry.getValue().size(); j++) { sumT1 += Math.pow(entry.getValue().get(j), 1); sumT2 += Math.pow(entry.getValue().get(j), 2); sumT3 += Math.pow(entry.getValue().get(j), 3); sumT4 += Math.pow(entry.getValue().get(j), 4); sumY += entry.getKey(); sumYxT1 += entry.getKey() * entry.getValue().get(j); sumYxT2 += entry.getKey() * Math.pow(entry.getValue().get(j), 2); } } */ DoubleMatrix firstMatrix = new DoubleMatrix(new double[][]{{n,sumT1,sumT2},{sumT1,sumT2,sumT3},{sumT2,sumT3,sumT4}}); DoubleMatrix secondMatrix = new DoubleMatrix( new double[]{sumY, sumYxT1, sumYxT2}); DoubleMatrix solvedMatrix = Solve.solve(firstMatrix,secondMatrix); //System.out.println(solvedMatrix); //return ((solvedMatrix.get(0)) + (solvedMatrix.get(1) * index) + (solvedMatrix.get(2) * Math.pow(index, 2))); //return ((solvedMatrix.get(1) * index) + (solvedMatrix.get(2) * Math.pow(index, 2)))*(-1); return ((solvedMatrix.get(1) * index) + (solvedMatrix.get(2) * Math.pow(index, 2))); } public static int getDataPointsXAxis() { return dataPointsXAxis; } public static int getDataPointsYAxis() { return dataPointsYAxis; } public static Map<String, Number> getLiveData() { return liveData; } public static void setLiveData(Map<String, Number> input) { liveData = input; } public static XYChart.Series<String, Number> getLiveDataSeries() { return liveDataSeries; } public static void setRegressionSeries(XYChart.Series<String, Number> regressionSeries) { LineChartFunctionality.regressionSeries = regressionSeries; } public static XYChart.Series<String, Number> getRegressionSeries() { return regressionSeries; } public static boolean isPrintRegression() { return printRegression; } public static void setPrintRegression(boolean printRegression) { LineChartFunctionality.printRegression = printRegression; } public static boolean isPrintRegressionConfidenceInterval() { return printRegressionConfidenceInterval; } public static void setPrintRegressionConfidenceInterval(boolean printRegressionConfidenceInterval) { LineChartFunctionality.printRegressionConfidenceInterval = printRegressionConfidenceInterval; } public static boolean isPrintLiveData() { return printLiveData; } public static void setPrintLiveData(boolean printLiveData) { LineChartFunctionality.printLiveData = printLiveData; } public static boolean isPrintPreviousData() { return printPreviousData; } public static void setPrintPreviousData(boolean printPreviousData) { LineChartFunctionality.printPreviousData = printPreviousData; } public static ArrayList<XYChart.Series<String, Number>> getPreviousData() { return previousData; } public static void addPreviousData(XYChart.Series<String, Number> previousData) { LineChartFunctionality.previousData.add(previousData); } public static XYChart.Series<String, Number> getRegressionSeriesConfidenceInterval() { return regressionSeriesConfidenceInterval; } public static void setRegressionSeriesConfidenceInterval(XYChart.Series<String, Number> regressionSeriesConfidenceInterval) { LineChartFunctionality.regressionSeriesConfidenceInterval = regressionSeriesConfidenceInterval; } public static LineChart<String, Number> getLineChart() { return lineChart; } public static void updateLineChart(XYChart.Series<String, Number> series) { getLineChart().getData().add(series); series.getNode().setId("dataGraphs"); getLineChart().getStylesheets().add(LineChartFunctionality.class.getResource("/com.application/GUI/graphStyles.css").toExternalForm()); } public static void clearLineChart() { getLineChart().getData().clear(); //lineChart.getData(). } }