Search in sources :

Example 71 with Plot

use of ij.gui.Plot in project GDSC-SMLM by aherbert.

the class PcPalmFitting method analyse.

/**
 * Perform the PC Analysis.
 *
 * <p>Spatial domain results can just be combined to an average curve.
 *
 * <p>Frequency domain results can be fit using the g(r) model.
 */
private void analyse() {
    latestResult.set(new CorrelationCurveResult(gr, peakDensity, spatialDomain));
    String axisTitle;
    if (spatialDomain) {
        offset = 0;
        axisTitle = "molecules/um^2";
    } else {
        // Ignore the r=0 value by starting with an offset if necessary
        offset = (gr[0][0] == 0) ? 1 : 0;
        axisTitle = "g(r)";
    }
    final String title = TITLE + " " + axisTitle;
    final Plot plot = PcPalmAnalysis.plotCorrelation(gr, offset, title, axisTitle, spatialDomain, settings.showErrorBars);
    if (spatialDomain) {
        saveCorrelationCurve(gr);
        IJ.log("Created correlation curve from the spatial domain (Plot title = " + title + ")");
        return;
    }
    // -------------
    // Model fitting for g(r) correlation curves
    // -------------
    IJ.log("Fitting g(r) correlation curve from the frequency domain");
    ImageJUtils.log("Average peak density = %s um^-2. Blinking estimate = %s", MathUtils.rounded(peakDensity, 4), MathUtils.rounded(settings.blinkingRate, 4));
    resultsTable = createResultsTable();
    // Get the protein density in nm^2.
    final double peakDensityNm2 = peakDensity / 1e6;
    // Use the blinking rate estimate to estimate the density
    // (factors in the over-counting of the same molecules)
    final double proteinDensity = peakDensityNm2 / settings.blinkingRate;
    final ArrayList<double[]> curves = new ArrayList<>();
    // Fit the g(r) curve for r>0 to equation 2
    Color color = Color.red;
    String resultColour = "Red";
    double[] parameters = fitRandomModel(gr, settings.estimatedPrecision, proteinDensity, resultColour);
    if (parameters != null) {
        ImageJUtils.log("  Plot %s: Over-counting estimate = %s", randomModel.getName(), MathUtils.rounded(peakDensityNm2 / parameters[1], 4));
        ImageJUtils.log("  Plot %s == %s", randomModel.getName(), resultColour);
        plot.setColor(color);
        plot.addPoints(randomModel.getX(), randomModel.value(parameters), Plot.LINE);
        addNonFittedPoints(plot, gr, randomModel, parameters);
        ImageJUtils.display(title, plot);
        if (settings.saveCorrelationCurve) {
            curves.add(extractCurve(gr, randomModel, parameters));
        }
    }
    // Fit the clustered models if the random model fails or if chosen as an option
    if (!valid1 || settings.fitClusteredModels) {
        // Fit the g(r) curve for r>0 to equation 3
        color = Color.blue;
        resultColour = "Blue";
        parameters = fitClusteredModel(gr, settings.estimatedPrecision, proteinDensity, resultColour);
        if (parameters != null) {
            ImageJUtils.log("  Plot %s: Over-counting estimate = %s", clusteredModel.getName(), MathUtils.rounded(peakDensityNm2 / parameters[1], 4));
            ImageJUtils.log("  Plot %s == %s", clusteredModel.getName(), resultColour.toString());
            plot.setColor(color);
            plot.addPoints(clusteredModel.getX(), clusteredModel.value(parameters), Plot.LINE);
            addNonFittedPoints(plot, gr, clusteredModel, parameters);
            ImageJUtils.display(title, plot);
            if (settings.saveCorrelationCurve) {
                curves.add(extractCurve(gr, clusteredModel, parameters));
            }
        }
        // Fit to an emulsion model for a distribution confined to circles
        color = Color.magenta;
        resultColour = "Magenta";
        parameters = fitEmulsionModel(gr, settings.estimatedPrecision, proteinDensity, resultColour);
        if (parameters != null) {
            ImageJUtils.log("  Plot %s: Over-counting estimate = %s", emulsionModel.getName(), MathUtils.rounded(peakDensityNm2 / parameters[1], 4));
            ImageJUtils.log("  Plot %s == %s", emulsionModel.getName(), resultColour.toString());
            plot.setColor(color);
            plot.addPoints(emulsionModel.getX(), emulsionModel.value(parameters), Plot.LINE);
            addNonFittedPoints(plot, gr, emulsionModel, parameters);
            ImageJUtils.display(title, plot);
            if (settings.saveCorrelationCurve) {
                curves.add(extractCurve(gr, emulsionModel, parameters));
            }
        }
    }
    saveCorrelationCurve(gr, curves.toArray(new double[0][0]));
}
Also used : Plot(ij.gui.Plot) Color(java.awt.Color) ArrayList(java.util.ArrayList)

Example 72 with Plot

use of ij.gui.Plot in project GDSC-SMLM by aherbert.

the class Fire method run.

@Override
public void run(String arg) {
    extraOptions = ImageJUtils.isExtraOptions();
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    // Require some fit results and selected regions
    final int size = MemoryPeakResults.countMemorySize();
    if (size == 0) {
        IJ.error(pluginTitle, "There are no fitting results in memory");
        return;
    }
    settings = Settings.load();
    settings.save();
    if ("q".equals(arg)) {
        pluginTitle += " Q estimation";
        runQEstimation();
        return;
    }
    IJ.showStatus(pluginTitle + " ...");
    if (!showInputDialog()) {
        return;
    }
    MemoryPeakResults inputResults1 = ResultsManager.loadInputResults(settings.inputOption, false, null, null);
    if (MemoryPeakResults.isEmpty(inputResults1)) {
        IJ.error(pluginTitle, "No results could be loaded");
        return;
    }
    MemoryPeakResults inputResults2 = ResultsManager.loadInputResults(settings.inputOption2, false, null, null);
    inputResults1 = cropToRoi(inputResults1);
    if (inputResults1.size() < 2) {
        IJ.error(pluginTitle, "No results within the crop region");
        return;
    }
    if (inputResults2 != null) {
        inputResults2 = cropToRoi(inputResults2);
        if (inputResults2.size() < 2) {
            IJ.error(pluginTitle, "No results2 within the crop region");
            return;
        }
    }
    initialise(inputResults1, inputResults2);
    if (!showDialog()) {
        return;
    }
    final long start = System.currentTimeMillis();
    // Compute FIRE
    String name = inputResults1.getName();
    final double fourierImageScale = Settings.scaleValues[settings.imageScaleIndex];
    final int imageSize = Settings.imageSizeValues[settings.imageSizeIndex];
    if (this.results2 != null) {
        name += " vs " + this.results2.getName();
        final FireResult result = calculateFireNumber(fourierMethod, samplingMethod, thresholdMethod, fourierImageScale, imageSize);
        if (result != null) {
            logResult(name, result);
            if (settings.showFrcCurve) {
                showFrcCurve(name, result, thresholdMethod);
            }
        }
    } else {
        FireResult result = null;
        final int repeats = (settings.randomSplit) ? Math.max(1, settings.repeats) : 1;
        setProgress(repeats);
        if (repeats == 1) {
            result = calculateFireNumber(fourierMethod, samplingMethod, thresholdMethod, fourierImageScale, imageSize);
            if (result != null) {
                logResult(name, result);
                if (settings.showFrcCurve) {
                    showFrcCurve(name, result, thresholdMethod);
                }
            }
        } else {
            // Multi-thread this ...
            final int nThreads = MathUtils.min(repeats, getThreads());
            final ExecutorService executor = Executors.newFixedThreadPool(nThreads);
            final LocalList<Future<?>> futures = new LocalList<>(repeats);
            final LocalList<FireWorker> workers = new LocalList<>(repeats);
            IJ.showProgress(0);
            IJ.showStatus(pluginTitle + " computing ...");
            for (int i = 1; i <= repeats; i++) {
                final FireWorker w = new FireWorker(i, fourierImageScale, imageSize);
                workers.add(w);
                futures.add(executor.submit(w));
            }
            // Wait for all to finish
            executor.shutdown();
            ConcurrencyUtils.waitForCompletionUnchecked(futures);
            IJ.showProgress(1);
            // Show a combined FRC curve plot of all the smoothed curves if we have multiples.
            final LUT valuesLut = LutHelper.createLut(LutColour.FIRE_GLOW);
            final LutHelper.DefaultLutMapper mapper = new LutHelper.DefaultLutMapper(0, repeats);
            final FrcCurvePlot curve = new FrcCurvePlot();
            final Statistics stats = new Statistics();
            final WindowOrganiser wo = new WindowOrganiser();
            boolean oom = false;
            for (int i = 0; i < repeats; i++) {
                final FireWorker w = workers.get(i);
                if (w.oom) {
                    oom = true;
                }
                if (w.result == null) {
                    continue;
                }
                result = w.result;
                if (!Double.isNaN(result.fireNumber)) {
                    stats.add(result.fireNumber);
                }
                if (settings.showFrcCurveRepeats) {
                    // Output each FRC curve using a suffix.
                    logResult(w.name, result);
                    wo.add(ImageJUtils.display(w.plot.getTitle(), w.plot));
                }
                if (settings.showFrcCurve) {
                    final int index = mapper.map(i + 1);
                    curve.add(name, result, thresholdMethod, LutHelper.getColour(valuesLut, index), Color.blue, null);
                }
            }
            if (result != null) {
                wo.cascade();
                final double mean = stats.getMean();
                logResult(name, result, mean, stats);
                if (settings.showFrcCurve) {
                    curve.addResolution(mean);
                    final Plot plot = curve.getPlot();
                    ImageJUtils.display(plot.getTitle(), plot);
                }
            }
            if (oom) {
                // @formatter:off
                IJ.error(pluginTitle, "ERROR - Parallel computation out-of-memory.\n \n" + TextUtils.wrap("The number of results will be reduced. " + "Please reduce the size of the Fourier image " + "or change the number of threads " + "using the extra options (hold down the 'Shift' " + "key when running the plugin).", 80));
            // @formatter:on
            }
        }
        // Only do this once
        if (settings.showFrcTimeEvolution && result != null && !Double.isNaN(result.fireNumber)) {
            showFrcTimeEvolution(name, result.fireNumber, thresholdMethod, nmPerUnit / result.getNmPerPixel(), imageSize);
        }
    }
    IJ.showStatus(pluginTitle + " complete : " + TextUtils.millisToString(System.currentTimeMillis() - start));
}
Also used : FrcFireResult(uk.ac.sussex.gdsc.smlm.ij.frc.Frc.FrcFireResult) Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) LUT(ij.process.LUT) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) DescriptiveStatistics(org.apache.commons.math3.stat.descriptive.DescriptiveStatistics) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) LutHelper(uk.ac.sussex.gdsc.core.ij.process.LutHelper) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)

Example 73 with Plot

use of ij.gui.Plot in project GDSC-SMLM by aherbert.

the class Fire method runQEstimation.

@SuppressWarnings("null")
private void runQEstimation() {
    IJ.showStatus(pluginTitle + " ...");
    if (!showQEstimationInputDialog()) {
        return;
    }
    MemoryPeakResults inputResults = ResultsManager.loadInputResults(settings.inputOption, false, null, null);
    if (MemoryPeakResults.isEmpty(inputResults)) {
        IJ.error(pluginTitle, "No results could be loaded");
        return;
    }
    if (inputResults.getCalibration() == null) {
        IJ.error(pluginTitle, "The results are not calibrated");
        return;
    }
    inputResults = cropToRoi(inputResults);
    if (inputResults.size() < 2) {
        IJ.error(pluginTitle, "No results within the crop region");
        return;
    }
    initialise(inputResults, null);
    // We need localisation precision.
    // Build a histogram of the localisation precision.
    // Get the initial mean and SD and plot as a Gaussian.
    final PrecisionHistogram histogram = calculatePrecisionHistogram();
    if (histogram == null) {
        IJ.error(pluginTitle, "No localisation precision available.\n \nPlease choose " + PrecisionMethod.FIXED + " and enter a precision mean and SD.");
        return;
    }
    final StoredDataStatistics precision = histogram.precision;
    final double fourierImageScale = Settings.scaleValues[settings.imageScaleIndex];
    final int imageSize = Settings.imageSizeValues[settings.imageSizeIndex];
    // Create the image and compute the numerator of FRC.
    // Do not use the signal so results.size() is the number of localisations.
    IJ.showStatus("Computing FRC curve ...");
    final FireImages images = createImages(fourierImageScale, imageSize, false);
    // DEBUGGING - Save the two images to disk. Load the images into the Matlab
    // code that calculates the Q-estimation and make this plugin match the functionality.
    // IJ.save(new ImagePlus("i1", images.ip1), "/scratch/i1.tif");
    // IJ.save(new ImagePlus("i2", images.ip2), "/scratch/i2.tif");
    final Frc frc = new Frc();
    frc.setTrackProgress(progress);
    frc.setFourierMethod(fourierMethod);
    frc.setSamplingMethod(samplingMethod);
    frc.setPerimeterSamplingFactor(settings.perimeterSamplingFactor);
    final FrcCurve frcCurve = frc.calculateFrcCurve(images.ip1, images.ip2, images.nmPerPixel);
    if (frcCurve == null) {
        IJ.error(pluginTitle, "Failed to compute FRC curve");
        return;
    }
    IJ.showStatus("Running Q-estimation ...");
    // Note:
    // The method implemented here is based on Matlab code provided by Bernd Rieger.
    // The idea is to compute the spurious correlation component of the FRC Numerator
    // using an initial estimate of distribution of the localisation precision (assumed
    // to be Gaussian). This component is the contribution of repeat localisations of
    // the same molecule to the numerator and is modelled as an exponential decay
    // (exp_decay). The component is scaled by the Q-value which
    // is the average number of times a molecule is seen in addition to the first time.
    // At large spatial frequencies the scaled component should match the numerator,
    // i.e. at high resolution (low FIRE number) the numerator is made up of repeat
    // localisations of the same molecule and not actual structure in the image.
    // The best fit is where the numerator equals the scaled component, i.e. num / (q*exp_decay) ==
    // 1.
    // The FRC Numerator is plotted and Q can be determined by
    // adjusting Q and the precision mean and SD to maximise the cost function.
    // This can be done interactively by the user with the effect on the FRC curve
    // dynamically updated and displayed.
    // Compute the scaled FRC numerator
    final double qNorm = (1 / frcCurve.mean1 + 1 / frcCurve.mean2);
    final double[] frcnum = new double[frcCurve.getSize()];
    for (int i = 0; i < frcnum.length; i++) {
        final FrcCurveResult r = frcCurve.get(i);
        frcnum[i] = qNorm * r.getNumerator() / r.getNumberOfSamples();
    }
    // Compute the spatial frequency and the region for curve fitting
    final double[] q = Frc.computeQ(frcCurve, false);
    int low = 0;
    int high = q.length;
    while (high > 0 && q[high - 1] > settings.maxQ) {
        high--;
    }
    while (low < q.length && q[low] < settings.minQ) {
        low++;
    }
    // Require we fit at least 10% of the curve
    if (high - low < q.length * 0.1) {
        IJ.error(pluginTitle, "Not enough points for Q estimation");
        return;
    }
    // Obtain initial estimate of Q plateau height and decay.
    // This can be done by fitting the precision histogram and then fixing the mean and sigma.
    // Or it can be done by allowing the precision to be sampled and the mean and sigma
    // become parameters for fitting.
    // Check if we can sample precision values
    final boolean sampleDecay = precision != null && settings.sampleDecay;
    double[] expDecay;
    if (sampleDecay) {
        // Random sample of precision values from the distribution is used to
        // construct the decay curve
        final int[] sample = RandomUtils.sample(10000, precision.getN(), UniformRandomProviders.create());
        final double four_pi2 = 4 * Math.PI * Math.PI;
        final double[] pre = new double[q.length];
        for (int i = 1; i < q.length; i++) {
            pre[i] = -four_pi2 * q[i] * q[i];
        }
        // Sample
        final int n = sample.length;
        final double[] hq = new double[n];
        for (int j = 0; j < n; j++) {
            // Scale to SR pixels
            double s2 = precision.getValue(sample[j]) / images.nmPerPixel;
            s2 *= s2;
            for (int i = 1; i < q.length; i++) {
                hq[i] += StdMath.exp(pre[i] * s2);
            }
        }
        for (int i = 1; i < q.length; i++) {
            hq[i] /= n;
        }
        expDecay = new double[q.length];
        expDecay[0] = 1;
        for (int i = 1; i < q.length; i++) {
            final double sinc_q = sinc(Math.PI * q[i]);
            expDecay[i] = sinc_q * sinc_q * hq[i];
        }
    } else {
        // Note: The sigma mean and std should be in the units of super-resolution
        // pixels so scale to SR pixels
        expDecay = computeExpDecay(histogram.mean / images.nmPerPixel, histogram.sigma / images.nmPerPixel, q);
    }
    // Smoothing
    double[] smooth;
    if (settings.loessSmoothing) {
        // Note: This computes the log then smooths it
        final double bandwidth = 0.1;
        final int robustness = 0;
        final double[] l = new double[expDecay.length];
        for (int i = 0; i < l.length; i++) {
            // Original Matlab code computes the log for each array.
            // This is equivalent to a single log on the fraction of the two.
            // Perhaps the two log method is more numerically stable.
            // l[i] = Math.log(Math.abs(frcnum[i])) - Math.log(exp_decay[i]);
            l[i] = Math.log(Math.abs(frcnum[i] / expDecay[i]));
        }
        try {
            final LoessInterpolator loess = new LoessInterpolator(bandwidth, robustness);
            smooth = loess.smooth(q, l);
        } catch (final Exception ex) {
            IJ.error(pluginTitle, "LOESS smoothing failed");
            return;
        }
    } else {
        // Note: This smooths the curve before computing the log
        final double[] norm = new double[expDecay.length];
        for (int i = 0; i < norm.length; i++) {
            norm[i] = frcnum[i] / expDecay[i];
        }
        // Median window of 5 == radius of 2
        final DoubleMedianWindow mw = DoubleMedianWindow.wrap(norm, 2);
        smooth = new double[expDecay.length];
        for (int i = 0; i < norm.length; i++) {
            smooth[i] = Math.log(Math.abs(mw.getMedian()));
            mw.increment();
        }
    }
    // Fit with quadratic to find the initial guess.
    // Note: example Matlab code frc_Qcorrection7.m identifies regions of the
    // smoothed log curve with low derivative and only fits those. The fit is
    // used for the final estimate. Fitting a subset with low derivative is not
    // implemented here since the initial estimate is subsequently optimised
    // to maximise a cost function.
    final Quadratic curve = new Quadratic();
    final SimpleCurveFitter fit = SimpleCurveFitter.create(curve, new double[2]);
    final WeightedObservedPoints points = new WeightedObservedPoints();
    for (int i = low; i < high; i++) {
        points.add(q[i], smooth[i]);
    }
    final double[] estimate = fit.fit(points.toList());
    double qvalue = StdMath.exp(estimate[0]);
    // This could be made an option. Just use for debugging
    final boolean debug = false;
    if (debug) {
        // Plot the initial fit and the fit curve
        final double[] qScaled = Frc.computeQ(frcCurve, true);
        final double[] line = new double[q.length];
        for (int i = 0; i < q.length; i++) {
            line[i] = curve.value(q[i], estimate);
        }
        final String title = pluginTitle + " Initial fit";
        final Plot plot = new Plot(title, "Spatial Frequency (nm^-1)", "FRC Numerator");
        final String label = String.format("Q = %.3f", qvalue);
        plot.addPoints(qScaled, smooth, Plot.LINE);
        plot.setColor(Color.red);
        plot.addPoints(qScaled, line, Plot.LINE);
        plot.setColor(Color.black);
        plot.addLabel(0, 0, label);
        ImageJUtils.display(title, plot, ImageJUtils.NO_TO_FRONT);
    }
    if (settings.fitPrecision) {
        // Q - Should this be optional?
        if (sampleDecay) {
            // If a sample of the precision was used to construct the data for the initial fit
            // then update the estimate using the fit result since it will be a better start point.
            histogram.sigma = precision.getStandardDeviation();
            // Normalise sum-of-squares to the SR pixel size
            final double meanSumOfSquares = (precision.getSumOfSquares() / (images.nmPerPixel * images.nmPerPixel)) / precision.getN();
            histogram.mean = images.nmPerPixel * Math.sqrt(meanSumOfSquares - estimate[1] / (4 * Math.PI * Math.PI));
        }
        // Do a multivariate fit ...
        final SimplexOptimizer opt = new SimplexOptimizer(1e-6, 1e-10);
        PointValuePair pair = null;
        final MultiPlateauness f = new MultiPlateauness(frcnum, q, low, high);
        final double[] initial = new double[] { histogram.mean / images.nmPerPixel, histogram.sigma / images.nmPerPixel, qvalue };
        pair = findMin(pair, opt, f, scale(initial, 0.1));
        pair = findMin(pair, opt, f, scale(initial, 0.5));
        pair = findMin(pair, opt, f, initial);
        pair = findMin(pair, opt, f, scale(initial, 2));
        pair = findMin(pair, opt, f, scale(initial, 10));
        if (pair != null) {
            final double[] point = pair.getPointRef();
            histogram.mean = point[0] * images.nmPerPixel;
            histogram.sigma = point[1] * images.nmPerPixel;
            qvalue = point[2];
        }
    } else {
        // If so then this should be optional.
        if (sampleDecay) {
            if (precisionMethod != PrecisionMethod.FIXED) {
                histogram.sigma = precision.getStandardDeviation();
                // Normalise sum-of-squares to the SR pixel size
                final double meanSumOfSquares = (precision.getSumOfSquares() / (images.nmPerPixel * images.nmPerPixel)) / precision.getN();
                histogram.mean = images.nmPerPixel * Math.sqrt(meanSumOfSquares - estimate[1] / (4 * Math.PI * Math.PI));
            }
            expDecay = computeExpDecay(histogram.mean / images.nmPerPixel, histogram.sigma / images.nmPerPixel, q);
        }
        // Estimate spurious component by promoting plateauness.
        // The Matlab code used random initial points for a Simplex optimiser.
        // A Brent line search should be pretty deterministic so do simple repeats.
        // However it will proceed downhill so if the initial point is wrong then
        // it will find a sub-optimal result.
        final UnivariateOptimizer o = new BrentOptimizer(1e-3, 1e-6);
        final Plateauness f = new Plateauness(frcnum, expDecay, low, high);
        UnivariatePointValuePair result = null;
        result = findMin(result, o, f, qvalue, 0.1);
        result = findMin(result, o, f, qvalue, 0.2);
        result = findMin(result, o, f, qvalue, 0.333);
        result = findMin(result, o, f, qvalue, 0.5);
        // Do some Simplex repeats as well
        final SimplexOptimizer opt = new SimplexOptimizer(1e-6, 1e-10);
        result = findMin(result, opt, f, qvalue * 0.1);
        result = findMin(result, opt, f, qvalue * 0.5);
        result = findMin(result, opt, f, qvalue);
        result = findMin(result, opt, f, qvalue * 2);
        result = findMin(result, opt, f, qvalue * 10);
        if (result != null) {
            qvalue = result.getPoint();
        }
    }
    final QPlot qplot = new QPlot(frcCurve, qvalue, low, high);
    // Interactive dialog to estimate Q (blinking events per flourophore) using
    // sliders for the mean and standard deviation of the localisation precision.
    showQEstimationDialog(histogram, qplot, images.nmPerPixel);
    IJ.showStatus(pluginTitle + " complete");
}
Also used : DoubleMedianWindow(uk.ac.sussex.gdsc.core.utils.DoubleMedianWindow) BrentOptimizer(org.apache.commons.math3.optim.univariate.BrentOptimizer) PointValuePair(org.apache.commons.math3.optim.PointValuePair) UnivariatePointValuePair(org.apache.commons.math3.optim.univariate.UnivariatePointValuePair) LoessInterpolator(org.apache.commons.math3.analysis.interpolation.LoessInterpolator) WeightedObservedPoints(org.apache.commons.math3.fitting.WeightedObservedPoints) FrcCurve(uk.ac.sussex.gdsc.smlm.ij.frc.Frc.FrcCurve) SimplexOptimizer(org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) FrcCurveResult(uk.ac.sussex.gdsc.smlm.ij.frc.Frc.FrcCurveResult) SimpleCurveFitter(org.apache.commons.math3.fitting.SimpleCurveFitter) Plot(ij.gui.Plot) HistogramPlot(uk.ac.sussex.gdsc.core.ij.HistogramPlot) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) UnivariatePointValuePair(org.apache.commons.math3.optim.univariate.UnivariatePointValuePair) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint) DataException(uk.ac.sussex.gdsc.core.data.DataException) ConversionException(uk.ac.sussex.gdsc.core.data.utils.ConversionException) Frc(uk.ac.sussex.gdsc.smlm.ij.frc.Frc) UnivariateOptimizer(org.apache.commons.math3.optim.univariate.UnivariateOptimizer)

Example 74 with Plot

use of ij.gui.Plot in project GDSC-SMLM by aherbert.

the class DriftCalculator method plotDrift.

private static PlotWindow plotDrift(PlotWindow parent, double[][] interpolated, double[][] original, String name, int index) {
    // Create plot
    final double[] xlimits = MathUtils.limits(interpolated[0]);
    double[] ylimits = MathUtils.limits(original[index]);
    ylimits = MathUtils.limits(ylimits, interpolated[index]);
    final Plot plot = new Plot(name, "Frame", "Drift (px)");
    plot.setLimits(xlimits[0], xlimits[1], ylimits[0], ylimits[1]);
    // De-saturated blue
    plot.setColor(new Color(0, 0, 155));
    plot.addPoints(original[0], original[index], Plot.CROSS);
    plot.setColor(java.awt.Color.RED);
    plot.addPoints(interpolated[0], interpolated[index], Plot.LINE);
    final WindowOrganiser wo = new WindowOrganiser();
    final PlotWindow window = ImageJUtils.display(name, plot, wo);
    if (wo.isNotEmpty() && parent != null) {
        final Point location = parent.getLocation();
        location.y += parent.getHeight();
        window.setLocation(location);
    }
    return window;
}
Also used : Plot(ij.gui.Plot) Color(java.awt.Color) PlotWindow(ij.gui.PlotWindow) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) Point(java.awt.Point)

Example 75 with Plot

use of ij.gui.Plot in project GDSC-SMLM by aherbert.

the class EmGainAnalysis method fit.

/**
 * Fit the EM-gain distribution (Gaussian * Gamma).
 *
 * @param histogram The distribution
 */
private void fit(int[] histogram) {
    final int[] limits = limits(histogram);
    final double[] x = getX(limits);
    final double[] y = getY(histogram, limits);
    Plot plot = new Plot(TITLE, "ADU", "Frequency");
    double yMax = MathUtils.max(y);
    plot.setLimits(limits[0], limits[1], 0, yMax);
    plot.setColor(Color.black);
    plot.addPoints(x, y, Plot.DOT);
    ImageJUtils.display(TITLE, plot);
    // Estimate remaining parameters.
    // Assuming a gamma_distribution(shape,scale) then mean = shape * scale
    // scale = gain
    // shape = Photons = mean / gain
    double mean = getMean(histogram) - settings.bias;
    // Note: if the bias is too high then the mean will be negative. Just move the bias.
    while (mean < 0) {
        settings.bias -= 1;
        mean += 1;
    }
    double photons = mean / settings.gain;
    if (settings.settingSimulate) {
        ImageJUtils.log("Simulated bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.settingBias, MathUtils.rounded(settings.settingGain), MathUtils.rounded(settings.settingNoise), MathUtils.rounded(settings.settingPhotons));
    }
    ImageJUtils.log("Estimate bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.bias, MathUtils.rounded(settings.gain), MathUtils.rounded(settings.noise), MathUtils.rounded(photons));
    final int max = (int) x[x.length - 1];
    double[] pg = pdf(max, photons, settings.gain, settings.noise, (int) settings.bias);
    plot.setColor(Color.blue);
    plot.addPoints(x, pg, Plot.LINE);
    ImageJUtils.display(TITLE, plot);
    // Perform a fit
    final CustomPowellOptimizer o = new CustomPowellOptimizer(1e-6, 1e-16, 1e-6, 1e-16);
    final double[] startPoint = new double[] { photons, settings.gain, settings.noise, settings.bias };
    int maxEval = 3000;
    final String[] paramNames = { "Photons", "Gain", "Noise", "Bias" };
    // Set bounds
    final double[] lower = new double[] { 0, 0.5 * settings.gain, 0, settings.bias - settings.noise };
    final double[] upper = new double[] { 2 * photons, 2 * settings.gain, settings.gain, settings.bias + settings.noise };
    // Restart until converged.
    // TODO - Maybe fix this with a better optimiser. This needs to be tested on real data.
    PointValuePair solution = null;
    for (int iter = 0; iter < 3; iter++) {
        IJ.showStatus("Fitting histogram ... Iteration " + iter);
        try {
            // Basic Powell optimiser
            final MultivariateFunction fun = getFunction(limits, y, max, maxEval);
            final PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(fun), GoalType.MINIMIZE, new InitialGuess((solution == null) ? startPoint : solution.getPointRef()));
            if (solution == null || optimum.getValue() < solution.getValue()) {
                final double[] point = optimum.getPointRef();
                // Check the bounds
                for (int i = 0; i < point.length; i++) {
                    if (point[i] < lower[i] || point[i] > upper[i]) {
                        throw new ComputationException(String.format("Fit out of of estimated range: %s %f", paramNames[i], point[i]));
                    }
                }
                solution = optimum;
            }
        } catch (final Exception ex) {
            IJ.log("Powell error: " + ex.getMessage());
            if (ex instanceof TooManyEvaluationsException) {
                maxEval = (int) (maxEval * 1.5);
            }
        }
        try {
            // Bounded Powell optimiser
            final MultivariateFunction fun = getFunction(limits, y, max, maxEval);
            final MultivariateFunctionMappingAdapter adapter = new MultivariateFunctionMappingAdapter(fun, lower, upper);
            PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(adapter), GoalType.MINIMIZE, new InitialGuess(adapter.boundedToUnbounded((solution == null) ? startPoint : solution.getPointRef())));
            final double[] point = adapter.unboundedToBounded(optimum.getPointRef());
            optimum = new PointValuePair(point, optimum.getValue());
            if (solution == null || optimum.getValue() < solution.getValue()) {
                solution = optimum;
            }
        } catch (final Exception ex) {
            IJ.log("Bounded Powell error: " + ex.getMessage());
            if (ex instanceof TooManyEvaluationsException) {
                maxEval = (int) (maxEval * 1.5);
            }
        }
    }
    ImageJUtils.finished();
    if (solution == null) {
        ImageJUtils.log("Failed to fit the distribution");
        return;
    }
    final double[] point = solution.getPointRef();
    photons = point[0];
    settings.gain = point[1];
    settings.noise = point[2];
    settings.bias = (int) Math.round(point[3]);
    final String label = String.format("Fitted bias=%d, gain=%s, noise=%s, photons=%s", (int) settings.bias, MathUtils.rounded(settings.gain), MathUtils.rounded(settings.noise), MathUtils.rounded(photons));
    ImageJUtils.log(label);
    if (settings.settingSimulate) {
        ImageJUtils.log("Relative Error bias=%s, gain=%s, noise=%s, photons=%s", MathUtils.rounded(relativeError(settings.bias, settings.settingBias)), MathUtils.rounded(relativeError(settings.gain, settings.settingGain)), MathUtils.rounded(relativeError(settings.noise, settings.settingNoise)), MathUtils.rounded(relativeError(photons, settings.settingPhotons)));
    }
    // Show the PoissonGammaGaussian approximation
    double[] approxValues = null;
    if (settings.showApproximation) {
        approxValues = new double[x.length];
        final PoissonGammaGaussianFunction fun = new PoissonGammaGaussianFunction(1.0 / settings.gain, settings.noise);
        final double expected = photons * settings.gain;
        for (int i = 0; i < approxValues.length; i++) {
            approxValues[i] = fun.likelihood(x[i] - settings.bias, expected);
        }
        yMax = MathUtils.maxDefault(yMax, approxValues);
    }
    // Replot
    pg = pdf(max, photons, settings.gain, settings.noise, (int) settings.bias);
    plot = new Plot(TITLE, "ADU", "Frequency");
    plot.setLimits(limits[0], limits[1], 0, yMax * 1.05);
    plot.setColor(Color.black);
    plot.addPoints(x, y, Plot.DOT);
    plot.setColor(Color.red);
    plot.addPoints(x, pg, Plot.LINE);
    plot.addLabel(0, 0, label);
    if (settings.showApproximation) {
        plot.setColor(Color.blue);
        plot.addPoints(x, approxValues, Plot.LINE);
    }
    ImageJUtils.display(TITLE, plot);
}
Also used : MaxEval(org.apache.commons.math3.optim.MaxEval) InitialGuess(org.apache.commons.math3.optim.InitialGuess) Plot(ij.gui.Plot) ObjectiveFunction(org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction) Point(java.awt.Point) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) TooManyEvaluationsException(org.apache.commons.math3.exception.TooManyEvaluationsException) PointValuePair(org.apache.commons.math3.optim.PointValuePair) MultivariateFunction(org.apache.commons.math3.analysis.MultivariateFunction) MultivariateFunctionMappingAdapter(org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionMappingAdapter) TooManyEvaluationsException(org.apache.commons.math3.exception.TooManyEvaluationsException) ComputationException(uk.ac.sussex.gdsc.core.data.ComputationException) CustomPowellOptimizer(uk.ac.sussex.gdsc.smlm.math3.optim.nonlinear.scalar.noderiv.CustomPowellOptimizer) PoissonGammaGaussianFunction(uk.ac.sussex.gdsc.smlm.function.PoissonGammaGaussianFunction)

Aggregations

Plot (ij.gui.Plot)89 HistogramPlot (uk.ac.sussex.gdsc.core.ij.HistogramPlot)20 Point (java.awt.Point)19 PlotWindow (ij.gui.PlotWindow)17 Color (java.awt.Color)13 WindowOrganiser (uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser)13 HistogramPlotBuilder (uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder)12 BasePoint (uk.ac.sussex.gdsc.core.match.BasePoint)12 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)11 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)11 Rectangle (java.awt.Rectangle)9 ArrayList (java.util.ArrayList)9 GenericDialog (ij.gui.GenericDialog)8 NonBlockingExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog)7 LocalList (uk.ac.sussex.gdsc.core.utils.LocalList)7 Statistics (uk.ac.sussex.gdsc.core.utils.Statistics)7 StoredData (uk.ac.sussex.gdsc.core.utils.StoredData)7 StoredDataStatistics (uk.ac.sussex.gdsc.core.utils.StoredDataStatistics)7 ImagePlus (ij.ImagePlus)6 TDoubleArrayList (gnu.trove.list.array.TDoubleArrayList)5