Search in sources :

Example 21 with Frequency

use of org.apache.commons.math3.stat.Frequency in project GDSC-SMLM by aherbert.

the class PcPalmMolecules method performDistanceAnalysis.

private void performDistanceAnalysis(double[][] intraHist, int p99) {
    // We want to know the fraction of distances between molecules at the 99th percentile
    // that are intra- rather than inter-molecule.
    // Do single linkage clustering of closest pair at this distance and count the number of
    // links that are inter and intra.
    // Convert molecules for clustering
    final ArrayList<ClusterPoint> points = new ArrayList<>(settings.molecules.size());
    for (final Molecule m : settings.molecules) {
        // Precision was used to store the molecule ID
        points.add(ClusterPoint.newClusterPoint((int) m.precision, m.x, m.y, m.photons));
    }
    final ClusteringEngine engine = new ClusteringEngine(Prefs.getThreads(), ClusteringAlgorithm.PARTICLE_SINGLE_LINKAGE, SimpleImageJTrackProgress.getInstance());
    IJ.showStatus("Clustering to check inter-molecule distances");
    engine.setTrackJoins(true);
    final List<Cluster> clusters = engine.findClusters(points, intraHist[0][p99]);
    IJ.showStatus("");
    if (clusters != null) {
        final double[] intraIdDistances = engine.getIntraIdDistances();
        final double[] interIdDistances = engine.getInterIdDistances();
        final int all = interIdDistances.length + intraIdDistances.length;
        log("  * Fraction of inter-molecule particle linkage @ %s nm = %s %%", MathUtils.rounded(intraHist[0][p99], 4), (all > 0) ? MathUtils.rounded(100.0 * interIdDistances.length / all, 4) : "0");
        // Show a double cumulative histogram plot
        final double[][] intraIdHist = MathUtils.cumulativeHistogram(intraIdDistances, false);
        final double[][] interIdHist = MathUtils.cumulativeHistogram(interIdDistances, false);
        // Plot
        final String title = TITLE + " molecule linkage distance";
        final Plot plot = new Plot(title, "Distance", "Frequency");
        plot.addPoints(intraIdHist[0], intraIdHist[1], Plot.LINE);
        double max = (intraIdHist[1].length > 0) ? intraIdHist[1][intraIdHist[1].length - 1] : 0;
        if (interIdHist[1].length > 0) {
            max = Math.max(max, interIdHist[1][interIdHist[1].length - 1]);
        }
        plot.setLimits(0, intraIdHist[0][intraIdHist[0].length - 1], 0, max);
        plot.setColor(Color.blue);
        plot.addPoints(interIdHist[0], interIdHist[1], Plot.LINE);
        plot.setColor(Color.black);
        plot.addLegend("Intra-molecule\nInter-molecule");
        ImageJUtils.display(title, plot);
    } else {
        log("Aborted clustering to check inter-molecule distances");
    }
}
Also used : Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) TDoubleArrayList(gnu.trove.list.array.TDoubleArrayList) ArrayList(java.util.ArrayList) Cluster(uk.ac.sussex.gdsc.core.clustering.Cluster) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint) ClusterPoint(uk.ac.sussex.gdsc.core.clustering.ClusterPoint) ClusteringEngine(uk.ac.sussex.gdsc.core.clustering.ClusteringEngine) ClusterPoint(uk.ac.sussex.gdsc.core.clustering.ClusterPoint)

Example 22 with Frequency

use of org.apache.commons.math3.stat.Frequency in project GDSC-SMLM by aherbert.

the class PcPalmClusters method run.

@Override
public void run(String arg) {
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    if (!showDialog()) {
        return;
    }
    PcPalmMolecules.logSpacer();
    ImageJUtils.log(TITLE);
    PcPalmMolecules.logSpacer();
    final long start = System.currentTimeMillis();
    HistogramData histogramData;
    if (fileInput) {
        histogramData = loadHistogram(settings.histogramFile);
    } else {
        histogramData = doClustering();
    }
    if (histogramData == null) {
        return;
    }
    final float[][] hist = histogramData.histogram;
    // Create a histogram of the cluster sizes
    String title = TITLE + " Molecules/cluster";
    final String xTitle = "Molecules/cluster";
    final String yTitle = "Frequency";
    // Plot the histogram
    Plot plot = new Plot(title, xTitle, yTitle);
    plot.addPoints(hist[0], hist[1], Plot.BAR);
    ImageJUtils.display(title, plot);
    final HistogramData noiseData = loadNoiseHistogram(histogramData);
    if (noiseData != null && subtractNoise(histogramData, noiseData)) {
        // Update the histogram
        title += " (noise subtracted)";
        plot = new Plot(title, xTitle, yTitle);
        plot.addPoints(hist[0], hist[1], Plot.BAR);
        ImageJUtils.display(title, plot);
        // Automatically save
        if (autoSave) {
            final String newFilename = FileUtils.replaceExtension(histogramData.filename, ".noise.tsv");
            if (saveHistogram(histogramData, newFilename)) {
                ImageJUtils.log("Saved noise-subtracted histogram to " + newFilename);
            }
        }
    }
    // Fit the histogram
    final double[] fitParameters = fitBinomial(histogramData);
    if (fitParameters != null) {
        // Add the binomial to the histogram
        final int n = (int) fitParameters[0];
        final double p = fitParameters[1];
        ImageJUtils.log("Optimal fit : N=%d, p=%s", n, MathUtils.rounded(p));
        final BinomialDistribution dist = new BinomialDistribution(n, p);
        // A zero-truncated binomial was fitted.
        // pi is the adjustment factor for the probability density.
        final double pi = 1 / (1 - dist.probability(0));
        if (!fileInput) {
            // Calculate the estimated number of clusters from the observed molecules:
            // Actual = (Observed / p-value) / N
            final double actual = (numberOfMolecules / p) / n;
            ImageJUtils.log("Estimated number of clusters : (%d / %s) / %d = %s", numberOfMolecules, MathUtils.rounded(p), n, MathUtils.rounded(actual));
        }
        final double[] x = new double[n + 2];
        final double[] y = new double[n + 2];
        // Scale the values to match those on the histogram
        final double normalisingFactor = count * pi;
        for (int i = 0; i <= n; i++) {
            x[i] = i;
            y[i] = dist.probability(i) * normalisingFactor;
        }
        x[n + 1] = n + 1;
        y[n + 1] = 0;
        // Redraw the plot since the limits may have changed
        plot.setColor(Color.magenta);
        plot.addPoints(x, y, Plot.LINE);
        plot.addPoints(x, y, Plot.CIRCLE);
        plot.setColor(Color.black);
        plot.updateImage();
        ImageJUtils.display(title, plot);
    }
    final double seconds = (System.currentTimeMillis() - start) / 1000.0;
    final String msg = TITLE + " complete : " + seconds + "s";
    IJ.showStatus(msg);
    ImageJUtils.log(msg);
}
Also used : Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) BinomialDistribution(org.apache.commons.math3.distribution.BinomialDistribution) ClusterPoint(uk.ac.sussex.gdsc.core.clustering.ClusterPoint)

Example 23 with Frequency

use of org.apache.commons.math3.stat.Frequency in project GDSC-SMLM by aherbert.

the class PcPalmMolecules method calculateAveragePrecision.

/**
 * Calculate the average precision by fitting a skewed Gaussian to the histogram of the precision
 * distribution.
 *
 * <p>A simple mean and SD of the histogram is computed. If the mean of the Skewed Gaussian does
 * not fit within 3 SDs of the simple mean then the simple mean is returned.
 *
 * @param molecules the molecules
 * @param title the plot title (null if no plot should be displayed)
 * @param histogramBins the histogram bins
 * @param logFitParameters Record the fit parameters to the ImageJ log
 * @param removeOutliers The distribution is created using all values within 1.5x the
 *        inter-quartile range (IQR) of the data
 * @return The average precision
 */
public double calculateAveragePrecision(List<Molecule> molecules, String title, int histogramBins, boolean logFitParameters, boolean removeOutliers) {
    // Plot histogram of the precision
    final float[] data = new float[molecules.size()];
    final DescriptiveStatistics stats = new DescriptiveStatistics();
    double yMin = Double.NEGATIVE_INFINITY;
    double yMax = 0;
    for (int i = 0; i < data.length; i++) {
        data[i] = (float) molecules.get(i).precision;
        stats.addValue(data[i]);
    }
    // Set the min and max y-values using 1.5 x IQR
    if (removeOutliers) {
        final double lower = stats.getPercentile(25);
        final double upper = stats.getPercentile(75);
        if (Double.isNaN(lower) || Double.isNaN(upper)) {
            if (logFitParameters) {
                ImageJUtils.log("Error computing IQR: %f - %f", lower, upper);
            }
        } else {
            final double iqr = upper - lower;
            yMin = Math.max(lower - iqr, stats.getMin());
            yMax = Math.min(upper + iqr, stats.getMax());
            if (logFitParameters) {
                ImageJUtils.log("  Data range: %f - %f. Plotting 1.5x IQR: %f - %f", stats.getMin(), stats.getMax(), yMin, yMax);
            }
        }
    }
    if (yMin == Double.NEGATIVE_INFINITY) {
        yMin = stats.getMin();
        yMax = stats.getMax();
        if (logFitParameters) {
            ImageJUtils.log("  Data range: %f - %f", yMin, yMax);
        }
    }
    int bins;
    if (histogramBins <= 0) {
        bins = (int) Math.ceil((stats.getMax() - stats.getMin()) / HistogramPlot.getBinWidthScottsRule(stats.getStandardDeviation(), (int) stats.getN()));
    } else {
        bins = histogramBins;
    }
    final float[][] hist = HistogramPlot.calcHistogram(data, yMin, yMax, bins);
    Plot plot = null;
    if (title != null) {
        plot = new Plot(title, "Precision", "Frequency");
        final float[] xValues = hist[0];
        final float[] yValues = hist[1];
        plot.addPoints(xValues, yValues, Plot.BAR);
        ImageJUtils.display(title, plot);
    }
    // Extract non-zero data
    float[] x = Arrays.copyOf(hist[0], hist[0].length);
    float[] y = Arrays.copyOf(hist[1], hist[1].length);
    int count = 0;
    for (int i = 0; i < y.length; i++) {
        if (y[i] > 0) {
            x[count] = x[i];
            y[count] = y[i];
            count++;
        }
    }
    x = Arrays.copyOf(x, count);
    y = Arrays.copyOf(y, count);
    // Sense check to fitted data. Get mean and SD of histogram
    final double[] stats2 = HistogramPlot.getHistogramStatistics(x, y);
    double mean = stats2[0];
    if (logFitParameters) {
        log("  Initial Statistics: %f +/- %f", stats2[0], stats2[1]);
    }
    // Standard Gaussian fit
    final double[] parameters = fitGaussian(x, y);
    if (parameters == null) {
        log("  Failed to fit initial Gaussian");
        return mean;
    }
    double newMean = parameters[1];
    double error = Math.abs(stats2[0] - newMean) / stats2[1];
    if (error > 3) {
        log("  Failed to fit Gaussian: %f standard deviations from histogram mean", error);
        return mean;
    }
    if (newMean < yMin || newMean > yMax) {
        log("  Failed to fit Gaussian: %f outside data range %f - %f", newMean, yMin, yMax);
        return mean;
    }
    mean = newMean;
    if (logFitParameters) {
        log("  Initial Gaussian: %f @ %f +/- %f", parameters[0], parameters[1], parameters[2]);
    }
    final double[] initialSolution = new double[] { parameters[0], parameters[1], parameters[2], -1 };
    // Fit to a skewed Gaussian (or appropriate function)
    final double[] skewParameters = fitSkewGaussian(x, y, initialSolution);
    if (skewParameters == null) {
        log("  Failed to fit Skewed Gaussian");
        return mean;
    }
    final SkewNormalFunction sn = new SkewNormalFunction(skewParameters);
    if (logFitParameters) {
        log("  Skewed Gaussian: %f @ %f +/- %f (a = %f) => %f +/- %f", skewParameters[0], skewParameters[1], skewParameters[2], skewParameters[3], sn.getMean(), Math.sqrt(sn.getVariance()));
    }
    newMean = sn.getMean();
    error = Math.abs(stats2[0] - newMean) / stats2[1];
    if (error > 3) {
        log("  Failed to fit Skewed Gaussian: %f standard deviations from histogram mean", error);
        return mean;
    }
    if (newMean < yMin || newMean > yMax) {
        log("  Failed to fit Skewed Gaussian: %f outside data range %f - %f", newMean, yMin, yMax);
        return mean;
    }
    // Use original histogram x-axis to maintain all the bins
    if (plot != null) {
        plot.setColor(Color.red);
        addToPlot(plot, hist[0], skewParameters, Plot.LINE);
        plot.setColor(Color.black);
        ImageJUtils.display(title, plot);
    }
    // Return the average precision from the fitted curve
    return newMean;
}
Also used : DescriptiveStatistics(org.apache.commons.math3.stat.descriptive.DescriptiveStatistics) Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) SkewNormalFunction(uk.ac.sussex.gdsc.smlm.function.SkewNormalFunction) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint) ClusterPoint(uk.ac.sussex.gdsc.core.clustering.ClusterPoint)

Aggregations

Plot (ij.gui.Plot)10 Plot2 (ij.gui.Plot2)7 WeightedObservedPoint (org.apache.commons.math3.fitting.WeightedObservedPoint)6 HistogramPlot (uk.ac.sussex.gdsc.core.ij.HistogramPlot)6 LinearInterpolator (org.apache.commons.math3.analysis.interpolation.LinearInterpolator)4 LoessInterpolator (org.apache.commons.math3.analysis.interpolation.LoessInterpolator)4 PolynomialSplineFunction (org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction)4 PointValuePair (org.apache.commons.math3.optim.PointValuePair)4 DescriptiveStatistics (org.apache.commons.math3.stat.descriptive.DescriptiveStatistics)4 ClusterPoint (gdsc.core.clustering.ClusterPoint)3 PlotWindow (ij.gui.PlotWindow)3 ArrayList (java.util.ArrayList)3 XorShift128PlusRandom (jcog.math.random.XorShift128PlusRandom)3 TooManyEvaluationsException (org.apache.commons.math3.exception.TooManyEvaluationsException)3 Frequency (org.apache.commons.math3.stat.Frequency)3 Test (org.junit.jupiter.api.Test)3 ClusterPoint (uk.ac.sussex.gdsc.core.clustering.ClusterPoint)3 StoredDataStatistics (gdsc.core.utils.StoredDataStatistics)2 TDoubleArrayList (gnu.trove.list.array.TDoubleArrayList)2 Point (java.awt.Point)2