/** * Utility to facilitate fitting data plotted in JFreeChart Provide data in JFReeChart format * (XYSeries), and retrieve univariate function parameters that best fit (using least squares) the * data. All data points will be weighted equally. * * <p>TODO: investigate whether weighting (possibly automatic weighting) can improve accuracy * * @param data xy series in JFReeChart format * @param type one of the Fitter.FunctionType predefined functions * @param guess initial guess for the fit. The number and meaning of these parameters depends on * the FunctionType. Implemented: Gaussian: 0: Normalization, 1: Mean 2: Sigma * @return array with parameters, whose meaning depends on the FunctionType. Use the function * getXYSeries to retrieve the XYDataset predicted by this fit */ public static double[] fit(XYSeries data, FunctionType type, double[] guess) { if (type == FunctionType.NoFit) { return null; } // create the commons math data object from the JFreeChart data object final WeightedObservedPoints obs = new WeightedObservedPoints(); for (int i = 0; i < data.getItemCount(); i++) { obs.add(1.0, data.getX(i).doubleValue(), data.getY(i).doubleValue()); } double[] result = null; switch (type) { case Pol1: final PolynomialCurveFitter fitter1 = PolynomialCurveFitter.create(1); result = fitter1.fit(obs.toList()); break; case Pol2: final PolynomialCurveFitter fitter2 = PolynomialCurveFitter.create(2); result = fitter2.fit(obs.toList()); break; case Pol3: final PolynomialCurveFitter fitter3 = PolynomialCurveFitter.create(3); result = fitter3.fit(obs.toList()); break; case Gaussian: final GaussianWithOffsetCurveFitter gf = GaussianWithOffsetCurveFitter.create(); if (guess != null) { gf.withStartPoint(guess); } result = gf.fit(obs.toList()); } return result; }
/** * Returns the average of the ys in a XYSeries * * @param data input data * @return y average */ public static double getYAvg(XYSeries data) { double avg = 0; for (int i = 0; i < data.getItemCount(); i++) { avg += data.getY(i).doubleValue(); } avg = avg / data.getItemCount(); return avg; }
/** * Returns <code>true</code> if all the y-values for the specified x-value are <code>null</code> * and <code>false</code> otherwise. * * @param x the x-value. * @return A boolean. */ protected boolean canPrune(Number x) { for (int s = 0; s < this.data.size(); s++) { XYSeries series = (XYSeries) this.data.get(s); if (series.getY(series.indexOf(x)) != null) { return false; } } return true; }
/** * Returns the value (the ordianate) of a point given its abscissa. * * @param abscissa abscissa of the considered point * @return return the value of the considered point (returns -1 if there is no points with the * given abscissa in the signal). */ public double getValueOfAbscissa(double abscissa) { int isInSeries = data.indexOf(abscissa); if (isInSeries >= 0) { return data.getY(isInSeries).doubleValue(); } else { System.out.println("There is no point whith the abscissa " + abscissa + " in the signal.\n"); return -1; } }
/** * Finds the x value corresponding to the maximum function value within the range of the provided * data set. * * @param type one of the Fitter.FunctionType predefined functions * @param parms parameters describing the function. These need to match the selected function or * an IllegalArgumentEception will be thrown * @param data JFreeChart series, used to bracket the range in which the maximum will be found * @return x value corresponding to the maximum function value */ public static double getXofMaxY(XYSeries data, FunctionType type, double[] parms) { double xAtMax = 0.0; double minX = data.getMinX(); double maxX = data.getMaxX(); switch (type) { case NoFit: // find the position in data with the highest y value double highestScore = data.getY(0).doubleValue(); int highestIndex = 0; for (int i = 1; i < data.getItemCount(); i++) { double newVal = data.getY(i).doubleValue(); if (newVal > highestScore) { highestScore = newVal; highestIndex = i; } } return data.getX(highestIndex).doubleValue(); case Pol1: case Pol2: case Pol3: checkParms(type, parms); PolynomialFunction derivativePolFunction = (new PolynomialFunction(parms)).polynomialDerivative(); final double relativeAccuracy = 1.0e-12; final double absoluteAccuracy = 1.0e-8; final int maxOrder = 5; UnivariateSolver solver = new BracketingNthOrderBrentSolver(relativeAccuracy, absoluteAccuracy, maxOrder); xAtMax = solver.solve(100, derivativePolFunction, minX, maxX); break; case Gaussian: // for a Gaussian we can take the mean and be sure it is the maximum // note that this may be outside our range of X values, but // this will be caught by our sanity checks below xAtMax = parms[1]; } // sanity checks if (xAtMax > maxX) xAtMax = maxX; if (xAtMax < minX) xAtMax = minX; return xAtMax; }
/** * Displays a signal (using the JFreeChart package). * * @param useChart if set to true, the signal is displaied as a bar chart (this is used for * histograms). */ public void display(boolean useChart) { JFreeChart chart; int nbSamples = getNbSamples(); if (useChart) { String[] categories = new String[nbSamples]; for (int i = 0; i < nbSamples; i++) { categories[i] = data.getX(i).toString(); } String[] categoryNames = {"Histogram"}; double[][] categoryData = new double[1][nbSamples]; for (int i = 0; i < nbSamples; i++) { categoryData[0][i] = data.getY(i).doubleValue(); } CategoryDataset categoryDataset = DatasetUtilities.createCategoryDataset(categoryNames, categories, categoryData); chart = ChartFactory.createBarChart( "Histogram", // Title "Data Value", // X axis label "Number of Elements", // Y axis label categoryDataset, // dataset PlotOrientation.VERTICAL, // orientation true, // legends true, // tool tips true); } else { XYDataset xyDataSet = new XYSeriesCollection(this.data); chart = ChartFactory.createXYLineChart( "Example Dataset", // Title "Abscissa", // X axis label "Ordinate", // Y axis label xyDataSet, // dataset PlotOrientation.VERTICAL, // orientation true, // legends true, // tool tips true); // urls XYPlot plot = (XYPlot) chart.getPlot(); XYItemRenderer r = plot.getRenderer(); if (r instanceof XYLineAndShapeRenderer) { XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r; renderer.setSeriesShapesVisible(0, true); renderer.setSeriesShapesFilled(0, true); } } ChartFrame frame = new ChartFrame("Frame Title", chart); frame.setVisible(true); frame.setSize(512, 512); }
/** * Calculates a measure for the goodness of fit as defined here: * http://en.wikipedia.org/wiki/Coefficient_of_determination R^2 = 1 - (SSres/SStot) where SSres = * SUM(i) (yi - fi)^2 end SStot = SUM(i) (yi - yavg)^2 * * @param data input data (raw data that were fitted * @param type function type used for fitting * @param parms function parameters derived in the fit * @return */ public static double getRSquare(XYSeries data, FunctionType type, double[] parms) { // calculate SStot double yAvg = getYAvg(data); double ssTot = 0.0; for (int i = 0; i < data.getItemCount(); i++) { double y = data.getY(i).doubleValue(); ssTot += (y - yAvg) * (y - yAvg); } // calculate SSres double ssRes = 0.0; for (int i = 0; i < data.getItemCount(); i++) { double y = data.getY(i).doubleValue(); double f = getFunctionValue(data.getX(i).doubleValue(), type, parms); ssRes += (y - f) * (y - f); } return 1.0 - (ssRes / ssTot); }
/** * Save the current signal in the file named filename. * * @param filename name of the file where to store the signal. */ public void save(String filename) { int nbSamples = this.getNbSamples(); String fileContent = "% Signal from Computer Exercise\n"; fileContent += "#" + nbSamples + "\n"; fileContent += "\n"; for (int i = 0; i < nbSamples; i++) { fileContent += data.getX(i) + "\t \t" + data.getY(i) + "\n"; } fileContent += "\n"; try { BufferedWriter out = new BufferedWriter(new FileWriter(filename)); out.write(fileContent); out.close(); } catch (IOException e) { System.out.println("Could not save file " + filename + " sorry...\n"); } }
/** * Gives the entered value at the index index. Caution ! No check is performed on the value of the * index (this method may throw an outofbound exception). * * @param index of the point (abscissa, value) * @return the corresponding value. */ public double getValueOfIndex(int index) { return data.getY(index).doubleValue(); }