/*
* Copyright (c) 2007-2012 The Broad Institute, Inc.
* SOFTWARE COPYRIGHT NOTICE
* This software and its documentation are the copyright of the Broad Institute, Inc. All rights are reserved.
*
* This software is supplied without any warranty or guaranteed support whatsoever. The Broad Institute is not responsible for its use, misuse, or functionality.
*
* This software is licensed under the terms of the GNU Lesser General Public License (LGPL),
* Version 2.1 which is available at http://www.opensource.org/licenses/lgpl-2.1.php.
*/
package org.broad.igv.data.seg;
import org.broad.igv.Globals;
import org.broad.igv.feature.Chromosome;
import org.broad.igv.feature.LocusScore;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.track.WindowFunction;
import java.util.*;
/**
* @author jrobinso
* @date Oct 13, 2010
*/
public class FreqData {
public static float DEFAULT_AMP_THRESHOLD = 0.1f;
public static float DEFAULT_DEL_THRESHOLD = -0.1f;
public static int DEFAULT_BIN_SIZE = 200000;
private float ampThreshold = DEFAULT_AMP_THRESHOLD;
private float delThreshold = DEFAULT_DEL_THRESHOLD;
private int binSize = DEFAULT_BIN_SIZE; // 200 kb bin size;
private SegmentedDataSet dataset;
private int numberOfSamples;
// private boolean logNormalized;
private Map<String, List<LocusScore>> amp;
private Map<String, List<LocusScore>> del;
private List<String> sampleNames;
Genome genome;
public FreqData(SegmentedDataSet ds, Genome genome) {
this.dataset = ds;
this.sampleNames = ds.getSampleNames();
numberOfSamples = sampleNames.size();
amp = new HashMap();
del = new HashMap();
this.genome = genome;
compute();
}
public void setParameters(int binSize, float delThreshold, float ampThreshold) {
this.binSize = binSize;
this.delThreshold = delThreshold;
this.ampThreshold = ampThreshold;
compute();
}
void compute() {
amp.clear();
del.clear();
int sizeInKB = (int) (genome.getNominalLength() / 1000);
int wgBinSize = sizeInKB / 700;
int wgBinCount = sizeInKB / wgBinSize + 1;
//Chromosome bins
for (String chr : genome.getAllChromosomeNames()) {
Chromosome c = genome.getChromosome(chr);
int len = c.getLength();
int nBins = len / binSize + 1;
List<LocusScore> ampBins = new ArrayList(nBins);
List<LocusScore> delBins = new ArrayList(nBins);
for (int i = 0; i < nBins; i++) {
int start = i * binSize;
int end = start + binSize;
ampBins.add(new Bin(chr, start, end));
delBins.add(new Bin(chr, start, end));
}
amp.put(chr, ampBins);
del.put(chr, delBins);
}
// Whole genome bins
List<LocusScore> ampBins = new ArrayList(wgBinCount);
List<LocusScore> delBins = new ArrayList(wgBinCount);
for (int i = 0; i < wgBinCount; i++) {
int start = i * wgBinSize;
int end = start + wgBinSize;
ampBins.add(new Bin(Globals.CHR_ALL, start, end));
delBins.add(new Bin(Globals.CHR_ALL, start, end));
}
amp.put(Globals.CHR_ALL, ampBins);
del.put(Globals.CHR_ALL, delBins);
// Chromsomes visible in whole genome view
Set<String> wgChromosomes = new HashSet<String>(genome.getLongChromosomeNames());
final boolean logNormalized = dataset.isLogNormalized();
for (String sample : sampleNames) {
for (String chr : genome.getLongChromosomeNames()) {
List<LocusScore> segments = dataset.getSegments(sample, chr);
if (segments != null) {
for (LocusScore seg : segments) {
final float segScore = logNormalized ? seg.getScore() :
(float) (Math.log(seg.getScore() / 2) / Globals.log2);
if (segScore > ampThreshold || segScore < delThreshold) {
int startBin = seg.getStart() / binSize;
int endBin = seg.getEnd() / binSize;
for (int b = startBin; b <= endBin; b++) {
if (b >= amp.get(chr).size()) {
break;
}
binCounts(chr, seg.getStart(), seg.getEnd(), segScore, b, binSize);
}
if (wgChromosomes.contains(chr)) {
int gStart = genome.getGenomeCoordinate(chr, seg.getStart());
int gEnd = genome.getGenomeCoordinate(chr, seg.getEnd());
int wgStartBin = gStart / wgBinSize;
int wgEndBin = gEnd / wgBinSize;
for (int b = wgStartBin; b <= wgEndBin; b++) {
if (b >= amp.get(Globals.CHR_ALL).size()) {
break;
}
binCounts(Globals.CHR_ALL, gStart, gEnd, segScore, b, wgBinSize);
}
}
}
}
}
}
}
}
private void binCounts(String chr, int segStart, int segEnd, float segScore, int b, int binSize) {
int binStart = b * binSize;
int binEnd = binStart + binSize;
// Weight by % overlap with bin
float weight = 1.0f;
if (segEnd < binEnd) {
int s = Math.max(segStart, binStart);
weight = ((float) (segEnd - s)) / binSize;
} else if (segStart > binStart) {
int e = Math.min(segEnd, binEnd);
weight = ((float) (e - segStart)) / binSize;
}
if (segScore > ampThreshold) {
Bin bin = (Bin) amp.get(chr).get(b);
bin.increment(weight, weight * segScore);
}
if (segScore < delThreshold) {
Bin bin = (Bin) del.get(chr).get(b);
bin.increment(-weight, weight * segScore);
}
}
// For testing
public void dumpData(String chr) {
System.out.println("track name=Amplifications");
for (Map.Entry<String, List<LocusScore>> entry : amp.entrySet()) {
if (!entry.getKey().equals(Globals.CHR_ALL)) {
for (LocusScore bin : entry.getValue()) {
System.out.println(bin.getChr() + "\t" + bin.getStart() + "\t" + bin.getEnd() + "\t" + bin.getScore());
}
}
}
//System.out.println("track name=Deletions");
//for(Bin bin : del.get(chr)) {
// System.out.println(bin.getChr() + "\t" + bin.getStart() + "\t" + bin.getEnd() + "\t" + bin.getCount());
//}
}
public int getNumberOfSamples() {
return numberOfSamples;
}
public List<LocusScore> getAmpCounts(String chr) {
return amp.get(chr);
}
public List<LocusScore> getDelCounts(String chr) {
return del.get(chr);
}
public float getAmpThreshold() {
return ampThreshold;
}
public float getDelThreshold() {
return delThreshold;
}
public class Bin implements LocusScore {
String chr;
int start;
int end;
float count;
private float totalCN;
Bin(String chr, int start, int end) {
this.chr = chr;
this.start = start;
this.end = end;
}
void increment(float count, float score) {
this.count += count;
totalCN = getTotalCN() + score;
}
float getCount() {
return count;
}
float getAvgCN() {
return count == 0 ? 0 : getTotalCN() / count;
}
public String getChr() {
return chr;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public void setStart(int start) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void setEnd(int end) {
//To change body of implemented methods use File | Settings | File Templates.
}
public float getScore() {
return getCount();
}
public LocusScore copy() {
return this; //To change body of implemented methods use File | Settings | File Templates.
}
public String getValueString(double position, WindowFunction windowFunction) {
int cnt = Math.abs(Math.round(count));
int percent = ((cnt * 100) / numberOfSamples);
return cnt + " (" + percent + "%)";
}
public float getTotalCN() {
return totalCN;
}
}
}