/**
* Copyright Copyright 2007-13 Simon Andrews
*
* This file is part of BamQC.
*
* BamQC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* BamQC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with BamQC; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Changelog:
* - Simon Andrews: Class creation.
*/
package uk.ac.babraham.BamQC.Utilities;
/**
* This class calculates a distribution of values for compacting multiple bars in a histogram.
* @author Simon Andrews
*/
public class CalculateDistribution {
double[] graphCounts = null;
private double[] distributionDouble = null;
private String[] xCategories = null;
private double[] rawCounts = null;
private double aboveMaxThreshold = 0L;
private double max = 0.0;
private int BIN_SIZE = 1;
public CalculateDistribution(double[] rawCounts,
double aboveMaxThreshold,
final int BIN_SIZE) {
this.rawCounts = rawCounts;
this.aboveMaxThreshold = aboveMaxThreshold;
this.BIN_SIZE = BIN_SIZE;
calculate();
}
public double[] getGraphCounts() {
return graphCounts;
}
public double[] getDistributionDouble() {
return distributionDouble;
}
public String[] getXCategories() {
return xCategories;
}
public double getMax() {
return max;
}
private void calculate() {
int maxLen = 0;
int minLen = -1;
prepareDistribution();
// Find the min and max lengths
for (int i=0;i<distributionDouble.length;i++) {
if (distributionDouble[i] > 0.0d) {
if (minLen < 0) {
minLen = i;
}
maxLen = i;
}
}
// We put one extra category either side of the actual size
if (minLen>0) minLen--;
maxLen++;
int [] startAndInterval = getSizeDistribution(minLen, maxLen);
// Work out how many categories we need
int categories = 0;
int currentValue = startAndInterval[0];
while (currentValue<= maxLen) {
++categories;
currentValue+= startAndInterval[1];
}
graphCounts = new double[categories];
xCategories = new String[categories];
for (int i=0;i<graphCounts.length;i++) {
int minValue = startAndInterval[0]+(startAndInterval[1]*i);
int maxValue = (startAndInterval[0]+(startAndInterval[1]*(i+1)))-1;
if (maxValue > maxLen) {
maxValue = maxLen;
}
for (int bp=minValue;bp<=maxValue;bp++) {
if (bp < distributionDouble.length) {
graphCounts[i] += distributionDouble[bp];
}
}
if (startAndInterval[1] == 1) {
xCategories[i] = ""+Integer.toString(minValue * 10);
}
else {
xCategories[i] = Integer.toString(minValue * 10)+"-"+Integer.toString(maxValue * 10);
}
if (graphCounts[i] > max) max = graphCounts[i];
}
}
private double percent(double value, double total) {
return (value / total) * 100.0;
}
private void prepareDistribution() {
// +2 = fraction and exceeding max values N
int binNumber = (rawCounts.length / BIN_SIZE) + 2;
distributionDouble = new double[binNumber];
double total = aboveMaxThreshold;
for (double count : rawCounts) {
total += count;
}
distributionDouble[binNumber - 1] = percent(aboveMaxThreshold, total);
for (int i = 0; i < rawCounts.length; i++) {
int index = (i / BIN_SIZE);
distributionDouble[index] += percent(rawCounts[i], total);
}
}
private int [] getSizeDistribution(int min, int max) {
int base = 1;
while (base > (max-min)) {
base /= 10;
}
int interval;
int starting;
int [] divisions = new int [] {1,2,5};
OUTER: while (true) {
for (int d=0;d<divisions.length;d++) {
int tester = base * divisions[d];
if (((max-min) / tester) <= 50) {
interval = tester;
break OUTER;
}
}
base *=10;
}
// Now we work out the first value to be plotted
int basicDivision = min/interval;
int testStart = basicDivision * interval;
starting = testStart;
return new int[] {starting,interval};
}
}