package gdsc.colocalisation.cda;
/*-----------------------------------------------------------------------------
* GDSC Plugins for ImageJ
*
* Copyright (C) 2011 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This class is based on the original CDA_Plugin developed by
* Maria Osorio-Reich:
* http://imagejdocu.tudor.lu/doku.php?id=plugin:analysis:confined_displacement_algorithm_determines_true_and_random_colocalization_:start
*---------------------------------------------------------------------------*/
import ij.gui.Plot;
import java.awt.Color;
/**
* Provides functionality to plot a histogram of sampleData and then determine if a value is
* significant using a specified p-value, i.e. it lies outside the upper/lower tails of the histogram sampleData.
*/
public class PlotResults
{
private Plot plot;
private String plotTitle = "";
private String plotYTitle = "";
private String plotXTitle = "";
private double[] probabilityLimits = null;
private String significanceTest = "";
private double[] normalisedHistogram;
private double[] sampleData;
private double[] histogramX;
private int[] histogramY;
private Color color = Color.blue;
private double sampleValue;
private double pValue = 0.05;
public PlotResults(double sampleValue, int bins, double[] sampleData, Color color)
{
createHistogram(sampleData, bins);
this.sampleValue = sampleValue;
this.color = color;
}
private void createHistogram(double[] sampleData, int bins)
{
this.sampleData = sampleData;
histogramX = new double[bins];
histogramY = new int[bins];
// Get the range
double min = Double.MAX_VALUE;
double max = -Double.MAX_VALUE;
for (int i = 0; i < sampleData.length; i++)
{
if (min > sampleData[i])
min = sampleData[i];
if (max < sampleData[i])
max = sampleData[i];
}
double interval = (max - min) / bins;
// Set the bins
for (int i = 0; i < bins; i++)
{
histogramX[i] = min + i * interval;
}
// Count the frequency
for (int i = 0; i < sampleData.length; i++)
{
int bin = (int) ((sampleData[i] - min) / interval);
if (bin >= bins)
bin = bins - 1;
if (bin < 0)
bin = 0;
histogramY[bin]++;
}
}
public void calculate(double pValue)
{
setPValue(pValue);
calculate();
}
public void calculate()
{
probabilityLimits = getProbabilityLimits(sampleData);
significanceTest = testSignificance(probabilityLimits, sampleValue);
normalisedHistogram = normaliseHistogram(histogramY);
plot = null;
}
private void createPlot()
{
double[] xValues = createHistogramAxis(histogramX);
double[] yValues = createHistogramValues(normalisedHistogram);
// Set the upper limit for the plot
double maxHistogram = 0;
for (double d : normalisedHistogram)
if (maxHistogram < d)
maxHistogram = d;
maxHistogram *= 1.05;
plot = new Plot(plotTitle, plotXTitle, plotYTitle, xValues, yValues, Plot.X_NUMBERS + Plot.Y_NUMBERS +
Plot.X_TICKS + Plot.Y_TICKS);
// Ensure the horizontal scale goes from 0 to 1 but add at least 0.05 to the limits.
double xMin = Math.min(xValues[0] - 0.05, Math.min(sampleValue - 0.05, 0));
double xMax = Math.max(xValues[xValues.length - 1] + 0.05, Math.max(sampleValue + 0.05, 1));
plot.setLimits(xMin, xMax, 0, maxHistogram * 1.05);
plot.setLineWidth(1);
plot.setColor(color);
plot.draw();
// Draw the significance lines and add top points
plot.drawLine(probabilityLimits[0], 0, probabilityLimits[0], maxHistogram);
plot.drawLine(probabilityLimits[1], 0, probabilityLimits[1], maxHistogram);
// Draw lines for the lower and upper probability limits
double[][] markers = new double[2][2];
markers[0][0] = probabilityLimits[0];
markers[0][1] = probabilityLimits[1];
markers[1][0] = maxHistogram;
markers[1][1] = maxHistogram;
plot.addPoints(markers[0], markers[1], 4);
// Draw line for the data value
double[][] valueMarker = new double[2][1];
valueMarker[0][0] = sampleValue;
valueMarker[1][0] = maxHistogram;
plot.setColor(Color.magenta);
plot.drawLine(sampleValue, 0, sampleValue, maxHistogram);
plot.addPoints(valueMarker[0], valueMarker[1], 0);
}
public void setXTitle(String title)
{
plotXTitle = title;
}
public void setYTitle(String title)
{
plotYTitle = title;
}
public void setTitle(String title)
{
plotTitle = title;
}
public Plot getPlot()
{
if (plot == null)
{
createPlot();
}
return plot;
}
public double[] getProbabilityLimits()
{
return probabilityLimits;
}
public String getSignificanceTest()
{
return significanceTest;
}
private double[] createHistogramAxis(double[] histogramX)
{
double[] axis = new double[histogramX.length * 2 + 2];
int index = 0;
for (int i = 0; i < histogramX.length; ++i)
{
axis[index++] = histogramX[i];
axis[index++] = histogramX[i];
}
double dx = (histogramX[1] - histogramX[0]);
axis[index++] = histogramX[histogramX.length - 1] + dx;
axis[index++] = histogramX[histogramX.length - 1] + dx;
return axis;
}
private double[] createHistogramValues(double[] histogramY)
{
double[] axis = new double[histogramY.length * 2 + 2];
int index = 0;
axis[index++] = 0;
for (int i = 0; i < histogramY.length; ++i)
{
axis[index++] = histogramY[i];
axis[index++] = histogramY[i];
}
axis[index++] = 0;
return axis;
}
private int getTotal(int[] histogram)
{
int total = 0;
for (int i : histogram)
total += i;
return total;
}
private double[] normaliseHistogram(int[] histogram)
{
int total = getTotal(histogram);
double[] normalised = new double[histogram.length];
for (int j = 0; j < histogram.length; ++j)
normalised[j] = ((double) histogram[j] / total);
return normalised;
}
private double[] getProbabilityLimits(double[] p)
{
double[] limits = new double[2];
int pCut = (int) Math.ceil(p.length * pValue);
limits[0] = p[pCut];
limits[1] = p[(p.length - pCut - 1)];
return limits;
}
private String testSignificance(double[] limits, double sampleValue)
{
String outputString = "";
if (sampleValue >= limits[1])
{
outputString = " Value is significant! (colocalised)";
}
else if (sampleValue <= limits[0])
{
outputString = " Value is significant! (not colocalised)";
}
else
{
outputString = " Value is NOT significant! ";
}
return outputString;
}
/**
* @param pValue
* the pValue to set
*/
public void setPValue(double pValue)
{
if (pValue >= 0 && pValue <= 1)
{
this.pValue = pValue;
}
else
{
throw new IllegalArgumentException("p-Value must be between 0 and 1: " + pValue);
}
}
/**
* @return the pValue
*/
public double getPValue()
{
return pValue;
}
}