/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.broad.igv.sam;
import org.broad.igv.feature.Locus;
import org.broad.igv.feature.LocusScore;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.renderer.DataRange;
import org.broad.igv.renderer.SequenceRenderer;
import org.broad.igv.tdf.TDFDataSource;
import org.broad.igv.tdf.TDFReader;
import org.broad.igv.track.*;
import org.broad.igv.ui.panel.IGVPopupMenu;
import org.broad.igv.ui.panel.ReferenceFrame;
import org.broad.igv.util.ResourceLocator;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Developmental track to explore display of conservation scores.
*
* @author jrobinso
*/
public class EWigTrack extends AbstractTrack {
// double dataMax;
char[] nucleotides = {'A', 'C', 'G', 'T'};
public static Color grey1 = new Color(230, 230, 230);
Map<Character, TDFDataSource> baseSources;
TDFDataSource tdfSource;
// TODO -- memory leak. This needs to get cleared when the gene list changes
private HashMap<String, LoadedInterval> loadedIntervalCache = new HashMap(200);
public EWigTrack(ResourceLocator locator, Genome genome) {
super(locator);
TDFReader reader = TDFReader.getReader(locator.getPath());
tdfSource = new TDFDataSource(reader, 4, "Pi", genome);
setDataRange(new DataRange(0, 0, 10));
baseSources = new HashMap();
for (int i = 0; i < 4; i++) {
TDFDataSource src = new TDFDataSource(reader, i, Character.toString(nucleotides[i]), genome);
baseSources.put(nucleotides[i], src);
}
}
@Override
public boolean isReadyToPaint(ReferenceFrame frame) {
final String chr = frame.getChrName();
final int start = (int) frame.getOrigin();
final int end = (int) frame.getEnd();
final int zoom = frame.getZoom();
LoadedInterval loadedInterval = loadedIntervalCache.get(frame.getName());
return (loadedInterval != null && loadedInterval.contains(chr, start, end, zoom));
}
@Override
public void load(ReferenceFrame context) {
final String chr = context.getChrName();
int start = (int) context.getOrigin();
int end = (int) context.getEnd();
final int zoom = context.getZoom();
// Expand start and end a bit for panning
int w = end - start;
start -= w / 2;
end += w / 2;
List<LocusScore> scores = tdfSource.getSummaryScoresForRange(chr,
(int) start,
end,
zoom);
Map<Character, List<LocusScore>> nScores = new HashMap();
for (Character c : nucleotides) {
nScores.put(c, baseSources.get(c).getSummaryScoresForRange(chr,
(int) start,
end,
zoom));
}
loadedIntervalCache.put(context.getName(), new LoadedInterval(chr, start, end, zoom, scores, nScores));
}
public void render(RenderContext context, Rectangle rect) {
paint(context, rect);
}
public boolean isLogNormalized() {
return false;
}
public float getRegionScore(String chr, int start, int end, int zoom, RegionScoreType type, String frameName) {
return 0;
}
private void paint(RenderContext context, Rectangle rect) {
ReferenceFrame frame = context.getReferenceFrame();
final String chr = frame.getChrName();
final int start = (int) frame.getOrigin();
final int end = (int) frame.getEnd();
final int zoom = frame.getZoom();
LoadedInterval loadedInterval = loadedIntervalCache.get(frame.getName());
if (loadedInterval == null || !loadedInterval.contains(chr, start, end, zoom)) {
return;
}
// The total score
List<LocusScore> scores = loadedInterval.scores;
Map<Character, List<LocusScore>> nScores = loadedInterval.baseScores;
Map<Character, Color> nucleotideColors = SequenceRenderer.getNucleotideColors();
for (int idx = 0; idx < scores.size(); idx++) {
LocusScore score = scores.get(idx);
int startPosition = score.getStart();
int endPosition = score.getEnd();
int pX = (int) (rect.getX() + (startPosition - context.getOrigin()) / context.getScale());
int dX = Math.max(1,
(int) (rect.getX() + (endPosition - context.getOrigin()) / context.getScale()) - pX);
if (dX > 4) {
dX -= 2;
pX++;
}
if (pX + dX < 0) {
continue;
} else if (pX > context.getVisibleRect().getMaxX()) {
break;
}
float totalCount = score.getScore();
int pY = (int) rect.getMaxY() - 1;
float dataMax = getDataRange().getMaximum();
double height = (totalCount * rect.getHeight() / dataMax);
height = Math.min(height, rect.height - 1);
for (char c : nucleotides) {
try {
LocusScore ns = nScores.get(c).get(idx);
float count = ns.getScore() * totalCount;
//pY = drawBar(context, idx, rect, dataMax, pY, pX, dX, c, count);
Graphics2D tGraphics = context.getGraphic2DForColor(nucleotideColors.get(c));
int h = (int) Math.round(count * height / totalCount);
h = Math.min(pY - rect.y, h);
int baseY = (int) (pY - h);
if (h > 0) {
tGraphics.fillRect(pX, baseY, dX, h);
}
pY = baseY;
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
// Draw border
context.getGraphic2DForColor(Color.gray).drawLine(
rect.x, rect.y + rect.height,
rect.x + rect.width, rect.y + rect.height);
// Draw scale
/*
DataRange range = getDataRange();
if (range != null) {
Graphics2D g = context.getGraphic2DForColor(Color.black);
Font font = g.getFont();
Font smallFont = FontManager.getScalableFont(8);
try {
g.setFont(smallFont);
String scale = "Scale: " + (int) range.getMinimum() + " - " +
(int) range.getMaximum();
g.drawString(scale, rect.x + 10, rect.y + 10);
} finally {
g.setFont(font);
}
}*/
}
public JPopupMenu getPopupMenu(
final MouseEvent evt) {
JPopupMenu popupMenu = new IGVPopupMenu();
JLabel popupTitle = new JLabel(" " + getName(), JLabel.CENTER);
Font newFont = popupMenu.getFont().deriveFont(Font.BOLD, 12);
popupTitle.setFont(newFont);
if (popupTitle != null) {
popupMenu.add(popupTitle);
}
popupMenu.addSeparator();
// addSortMenuItem(popupMenu);
// addPackMenuItem(popupMenu);
// addShadeBaseMenuItem(popupMenu);
// addCopyToClipboardItem(popupMenu, evt);
// addGoToMate(popupMenu, evt);
// popupMenu.addSeparator();
//JLabel trackSettingsHeading = new JLabel(" Track Settings",
// JLabel.LEFT);
//trackSettingsHeading.setFont(newFont);
//popupMenu.add(trackSettingsHeading);
ArrayList<Track> tmp = new ArrayList();
tmp.add(this);
popupMenu.add(TrackMenuUtils.getTrackRenameItem(tmp));
popupMenu.add(TrackMenuUtils.getChangeTrackHeightItem(tmp));
popupMenu.add(TrackMenuUtils.getDataRangeItem(tmp));
return popupMenu;
}
// public String getValueStringAt(String chr, double position, int y, ReferenceFrame frame) {
// return null;
// }
static public class LoadedInterval {
Locus range;
private List<LocusScore> scores;
int zoom;
Map<Character, List<LocusScore>> baseScores;
public LoadedInterval(String chr, int start, int end, int zoom,
List<LocusScore> scores,
Map<Character, List<LocusScore>> baseScores) {
range = new Locus(chr, start, end);
this.zoom = zoom;
this.scores = scores;
this.baseScores = baseScores;
}
public boolean contains(String chr, int start, int end, int zoom) {
return this.zoom == zoom && range.contains(chr, start, end);
}
}
}