/*
* 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.
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.broad.igv.sam;
import com.google.common.eventbus.Subscribe;
import org.apache.log4j.Logger;
import org.broad.igv.Globals;
import org.broad.igv.PreferenceManager;
import org.broad.igv.data.CoverageDataSource;
import org.broad.igv.feature.FeatureUtils;
import org.broad.igv.feature.LocusScore;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.goby.GobyCountArchiveDataSource;
import org.broad.igv.renderer.BarChartRenderer;
import org.broad.igv.renderer.DataRange;
import org.broad.igv.renderer.DataRenderer;
import org.broad.igv.session.IGVSessionReader;
import org.broad.igv.session.SubtlyImportant;
import org.broad.igv.tdf.TDFDataSource;
import org.broad.igv.tdf.TDFReader;
import org.broad.igv.track.*;
import org.broad.igv.ui.DataRangeDialog;
import org.broad.igv.ui.IGV;
import org.broad.igv.ui.color.ColorUtilities;
import org.broad.igv.ui.event.DataLoadedEvent;
import org.broad.igv.ui.event.ViewChange;
import org.broad.igv.ui.panel.FrameManager;
import org.broad.igv.ui.panel.IGVPopupMenu;
import org.broad.igv.ui.panel.ReferenceFrame;
import org.broad.igv.ui.util.FileDialogUtils;
import org.broad.igv.ui.util.MessageUtils;
import org.broad.igv.util.ResourceLocator;
import org.broad.igv.util.StringUtils;
import javax.swing.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author jrobinso
*/
@XmlType(factoryMethod = "getNextTrack")
public class CoverageTrack extends AbstractTrack {
private static Logger log = Logger.getLogger(CoverageTrack.class);
public static final int TEN_MB = 10000000;
char[] nucleotides = {'a', 'c', 'g', 't', 'n'};
public static Color lightBlue = new Color(0, 0, 150);
private static Color coverageGrey = new Color(175, 175, 175);
public static final Color negStrandColor = new Color(140, 140, 160);
public static final Color posStrandColor = new Color(160, 140, 140);
public static final boolean DEFAULT_AUTOSCALE = true;
public static final boolean DEFAULT_SHOW_REFERENCE = false;
// User settable state -- these attributes should be stored in the session file
@XmlAttribute private float snpThreshold;
//TODO This appears to not be used anywhere, remove?
@XmlAttribute boolean showReference;
AlignmentDataManager dataManager;
CoverageDataSource dataSource;
DataRenderer dataSourceRenderer;
IntervalRenderer intervalRenderer;
PreferenceManager prefs;
JMenuItem dataRangeItem;
JMenuItem autoscaleItem;
Genome genome;
/**
* Whether to autoscale across all ReferenceFrames
* Default is true because we usually do, SashimiPlot does not
*/
private boolean globalAutoScale = true;
public void setRenderOptions(AlignmentTrack.RenderOptions renderOptions) {
this.renderOptions = renderOptions;
}
AlignmentTrack.RenderOptions getRenderOptions(){
return this.renderOptions;
}
private AlignmentTrack.RenderOptions renderOptions = null;
public CoverageTrack(CoverageTrack track){
this(track.getResourceLocator(), track.getName(), track.genome);
if(track.dataManager != null) this.setDataManager(track.dataManager);
if(track.dataSource != null) this.setDataSource(track.dataSource);
}
public CoverageTrack(ResourceLocator locator, String name, Genome genome) {
super(locator, locator.getPath() + "_coverage", name);
super.setDataRange(new DataRange(0, 0, 60));
this.genome = genome;
intervalRenderer = new IntervalRenderer();
setMaximumHeight(40);
setColor(coverageGrey);
prefs = PreferenceManager.getInstance();
snpThreshold = prefs.getAsFloat(PreferenceManager.SAM_ALLELE_THRESHOLD);
autoScale = DEFAULT_AUTOSCALE;
showReference = DEFAULT_SHOW_REFERENCE;
//TODO logScale = prefs.
}
public void setDataManager(AlignmentDataManager dataManager) {
this.dataManager = dataManager;
this.dataManager.getEventBus().register(this);
}
public void setDataSource(CoverageDataSource dataSource) {
this.dataSource = dataSource;
dataSourceRenderer = new BarChartRenderer();
setDataRange(new DataRange(0, 0, 1.5f * (float) dataSource.getDataMax()));
}
public void setSnpThreshold(float snpThreshold){
this.snpThreshold = snpThreshold;
}
public float getSnpThreshold() {
return snpThreshold;
}
public boolean isShowReference() {
return showReference;
}
/**
* Rescale as necessary, and tell components to repaint
* @param e
*/
@Subscribe
public void receiveDataLoaded(DataLoadedEvent e){
ReferenceFrame frame = e.context.getReferenceFrame();
rescale(frame);
frame.getEventBus().post(new ViewChange.Result());
}
public void rescale(ReferenceFrame iframe) {
List<ReferenceFrame> frameList = new ArrayList<ReferenceFrame>();
if(iframe != null) frameList.add(iframe);
if(globalAutoScale){
frameList.addAll(FrameManager.getFrames());
}
if (autoScale && dataManager != null) {
int max = 10;
for (ReferenceFrame frame : frameList) {
AlignmentInterval interval = dataManager.getLoadedInterval(frame.getCurrentRange());
if (interval == null) continue;
int origin = (int) frame.getOrigin();
int end = (int) frame.getEnd() + 1;
int intervalMax = interval.getMaxCount(origin, end);
max = intervalMax > max ? intervalMax : max;
}
DataRange newRange = new DataRange(0, max);
newRange.setType(getDataRange().getType());
super.setDataRange(newRange);
}
}
public void render(RenderContext context, Rectangle rect){
overlay(context, rect);
drawBorder(context, rect);
List<LocusScore> scores = getSummaryScores(context);
if (scores != null) {
dataSourceRenderer.renderBorder(this, context, rect);
}
if(!isRepeatY(rect)){
lastRenderY = rect.y;
if(dataSourceRenderer != null){
dataSourceRenderer.renderAxis(this, context, rect);
}
if(FrameManager.isExomeMode()){
int x = context.getGraphics().getClipBounds().x;
Rectangle scaleRect = new Rectangle(x, rect.y, rect.width, rect.height);
drawScale(context, scaleRect);
}
}
}
private List<LocusScore> getSummaryScores(RenderContext context){
List<LocusScore> scores = null;
if(dataSource != null){
String chr = context.getChr();
int start = (int) context.getOrigin();
int end = (int) context.getEndLocation();
int zoom = context.getZoom();
scores = dataSource.getSummaryScoresForRange(chr, start, end, zoom);
}
return scores;
}
public void overlay(RenderContext context, Rectangle rect) {
float maxRange = PreferenceManager.getInstance().getAsFloat(PreferenceManager.SAM_MAX_VISIBLE_RANGE);
float minVisibleScale = (maxRange * 1000) / 700;
if (context.getScale() < minVisibleScale && !context.getChr().equals(Globals.CHR_ALL)) {
//Show coverage calculated from intervals if zoomed in enough
AlignmentInterval interval = null;
if (dataManager != null) {
dataManager.load(context, renderOptions, true);
interval = dataManager.getLoadedInterval(context.getReferenceFrame().getCurrentRange());
}
if (interval != null) {
if (interval.contains(context.getChr(), (int) context.getOrigin(), (int) context.getEndLocation())) {
if(autoScale) rescale(context.getReferenceFrame());
intervalRenderer.paint(context, rect, interval.getCounts());
return;
}
}
}
//Use precomputed scores, if available
List<LocusScore> scores = getSummaryScores(context);
if (scores != null) {
dataSourceRenderer.renderScores(this, scores, context, rect);
}
}
/**
* Draw border and scale
* @param context
* @param rect
*/
private void drawBorder(RenderContext context, Rectangle rect) {
context.getGraphic2DForColor(Color.gray).drawLine(
rect.x, rect.y + rect.height,
rect.x + rect.width, rect.y + rect.height);
if(!FrameManager.isExomeMode()){
drawScale(context, rect);
}
}
public void drawScale(RenderContext context, Rectangle rect) {
DataRenderer.drawScale(getDataRange(), context, rect);
}
public boolean isLogNormalized() {
return false;
}
public String getValueStringAt(String chr, double position, int y, ReferenceFrame frame) {
float maxRange = PreferenceManager.getInstance().getAsFloat(PreferenceManager.SAM_MAX_VISIBLE_RANGE);
float minVisibleScale = (maxRange * 1000) / 700;
if (frame.getScale() < minVisibleScale) {
AlignmentInterval interval = dataManager.getLoadedInterval(frame.getCurrentRange());
if (interval == null) return null;
if (interval.contains(chr, (int) position, (int) position)) {
AlignmentCounts counts = interval.getCounts();
if (counts != null) {
return counts.getValueStringAt((int) position);
}
}
} else {
return getPrecomputedValueString(chr, position, frame);
}
return null;
}
private String getPrecomputedValueString(String chr, double position, ReferenceFrame frame) {
if (dataSource == null) {
return "";
}
int zoom = Math.max(0, frame.getZoom());
List<LocusScore> scores = dataSource.getSummaryScoresForRange(chr, (int) position - 10, (int) position + 10, zoom);
// give a 2 pixel window, otherwise very narrow features will be missed.
double bpPerPixel = frame.getScale();
double minWidth = 2 * bpPerPixel; /* * */
if (scores == null) {
return "";
} else {
LocusScore score = (LocusScore) FeatureUtils.getFeatureAt(position, 0, scores);
return score == null ? "" : "Mean count: " + score.getScore();
}
}
public float getRegionScore(String chr, int start, int end, int zoom, RegionScoreType type, String frameName) {
return 0;
}
/**
* Class to render coverage track, including mismatches.
* <p/>
* NOTE: This class has been extensively optimized with the aid of a profiler, attempts to "clean up" this code
* should be done with frequent profiling, or it will likely have detrimental performance impacts.
*/
class IntervalRenderer {
private void paint(RenderContext context, Rectangle rect, AlignmentCounts alignmentCounts) {
Color color = getColor();
Graphics2D graphics = context.getGraphic2DForColor(color);
DataRange range = getDataRange();
double maxRange = range.isLog() ? Math.log10(range.getMaximum() + 1) : range.getMaximum();
final double rectX = rect.getX();
final double rectMaxX = rect.getMaxX();
final double rectY = rect.getY();
final double rectMaxY = rect.getMaxY();
final double rectHeight = rect.getHeight();
final double origin = context.getOrigin();
final double colorScaleMax = getColorScale().getMaximum();
final double scale = context.getScale();
boolean bisulfiteMode = dataManager.getExperimentType() == AlignmentTrack.ExperimentType.BISULFITE;
// First pass, coverage
int lastpX = -1;
//for (AlignmentCounts alignmentCounts : countList) {
int start = alignmentCounts.getStart();
int nPoints = alignmentCounts.getNumberOfPoints();
boolean isSparse = alignmentCounts instanceof SparseAlignmentCounts;
for (int idx = 0; idx < nPoints; idx++) {
int pos = isSparse ? ((SparseAlignmentCounts) alignmentCounts).getPosition(idx) : start + idx;
int pX = (int) (rectX + (pos - origin) / scale);
if (pX > rectMaxX) {
break; // We're done, data is position sorted so we're beyond the right-side of the view
}
int dX = (int) (rectX + (pos + 1 - origin) / scale) - pX;
dX = dX < 1 ? 1 : dX;
if (pX + dX > lastpX) {
int pY = (int) rectMaxY - 1;
int totalCount = alignmentCounts.getTotalCount(pos);
double tmp = range.isLog() ? Math.log10(totalCount + 1) / maxRange : totalCount / maxRange;
int height = (int) (tmp * rectHeight);
height = Math.min(height, rect.height - 1);
int topY = (pY - height);
if (dX > 3) {
dX--; // Create a little space between bars when there is room.
}
if (height > 0) {
graphics.fillRect(pX, topY, dX, height);
}
lastpX = pX + dX;
}
}
//}
// Second pass - mark mismatches
lastpX = -1;
//for (AlignmentCounts alignmentCounts : countList) {
BisulfiteCounts bisulfiteCounts = alignmentCounts.getBisulfiteCounts();
final int intervalEnd = alignmentCounts.getEnd();
final int intervalStart = alignmentCounts.getStart();
byte[] refBases = null;
// Dont try to compute mismatches for intervals > 10 MB
if ((intervalEnd - intervalStart) < TEN_MB) {
refBases = genome.getSequence(context.getChr(), intervalStart, intervalEnd);
}
start = alignmentCounts.getStart();
nPoints = alignmentCounts.getNumberOfPoints();
isSparse = alignmentCounts instanceof SparseAlignmentCounts;
for (int idx = 0; idx < nPoints; idx++) {
int pos = isSparse ? ((SparseAlignmentCounts) alignmentCounts).getPosition(idx) : start + idx;
BisulfiteCounts.Count bc = null;
if (bisulfiteMode && bisulfiteCounts != null) {
bc = bisulfiteCounts.getCount(pos);
}
int pX = (int) (rectX + (pos - origin) / scale);
if (pX > rectMaxX) {
break; // We're done, data is position sorted so we're beyond the right-side of the view
}
int dX = (int) (rectX + (pos + 1 - origin) / scale) - pX;
dX = dX < 1 ? 1 : dX;
if (pX + dX > lastpX) {
// Test to see if any single nucleotide mismatch (nucleotide other than the reference)
// has a quality weight > 20% of the total
// Skip this test if the position is in the list of known snps or if the reference is unknown
boolean mismatch = false;
if (refBases != null) {
int refIdx = pos - intervalStart;
if (refIdx >= 0 && refIdx < refBases.length) {
if (bisulfiteMode) {
mismatch = (bc != null && (bc.methylatedCount + bc.unmethylatedCount) > 0);
} else {
byte ref = refBases[refIdx];
mismatch = alignmentCounts.isMismatch(pos, ref, context.getChr(), snpThreshold);
}
}
}
if (!mismatch) {
continue;
}
int pY = (int) rectMaxY - 1;
int totalCount = alignmentCounts.getTotalCount(pos);
double tmp = range.isLog() ? Math.log10(totalCount + 1) / maxRange : totalCount / maxRange;
int height = (int) (tmp * rectHeight);
height = Math.min(height, rect.height - 1);
if (dX > 3) {
dX--; // Create a little space between bars when there is room.
}
if (height > 0) {
if (bisulfiteMode) {
if (bc != null) {
drawBarBisulfite(context, pos, rect, totalCount, maxRange,
pY, pX, dX, bc, range.isLog());
}
} else {
drawBar(context, pos, rect, totalCount, maxRange,
pY, pX, dX, alignmentCounts, range.isLog());
}
}
lastpX = pX + dX;
}
}
//}
}
}
/**
* Draw a colored bar to represent a mismatch to the reference. The height is proportional to the % of
* reads with respect to the total. If "showAllSnps == true" the bar is shaded by avg read quality.
*
* @param context
* @param pos
* @param rect
* @param max
* @param pY
* @param pX
* @param dX
* @param interval
* @return
*/
int drawBar(RenderContext context,
int pos,
Rectangle rect,
double totalCount,
double max,
int pY,
int pX,
int dX,
AlignmentCounts interval,
boolean isLog) {
for (char nucleotide : nucleotides) {
int count = interval.getCount(pos, (byte) nucleotide);
Color c = AlignmentRenderer.nucleotideColors.get(nucleotide);
Graphics2D tGraphics = context.getGraphic2DForColor(c);
double tmp = isLog ?
(count / totalCount) * Math.log10(totalCount + 1) / max :
count / max;
int height = (int) (tmp * rect.getHeight());
height = Math.min(pY - rect.y, height);
int baseY = pY - height;
if (height > 0) {
tGraphics.fillRect(pX, baseY, dX, height);
}
pY = baseY;
}
return pX + dX;
}
int drawBarBisulfite(RenderContext context,
int pos,
Rectangle rect,
double totalCount,
double maxRange,
int pY,
int pX0,
int dX,
BisulfiteCounts.Count count,
boolean isLog) {
// If bisulfite mode, we expand the rectangle to make it more visible. This code is copied from
// AlignmentRenderer
int pX = pX0;
if (dX < 3) {
int expansion = dX;
pX -= expansion;
dX += (2 * expansion);
}
double nMethylated = count.methylatedCount;
double unMethylated = count.unmethylatedCount;
Color c = Color.red;
Graphics2D tGraphics = context.getGraphic2DForColor(c);
//Not all reads at a position are informative, color by % of informative reads
// double totalInformative = count.methylatedCount + count.unmethylatedCount;
// double mult = totalCount / totalInformative;
// nMethylated *= mult;
// unMethylated *= mult;
double tmp = isLog ?
(nMethylated / totalCount) * Math.log10(totalCount + 1) / maxRange :
nMethylated / maxRange;
int height = (int) (tmp * rect.getHeight());
height = Math.min(pY - rect.y, height);
int baseY = pY - height;
if (height > 0) {
tGraphics.fillRect(pX, baseY, dX, height);
}
pY = baseY;
c = Color.blue;
tGraphics = context.getGraphic2DForColor(c);
tmp = isLog ?
(unMethylated / totalCount) * Math.log10(totalCount + 1) / maxRange :
unMethylated / maxRange;
height = (int) (tmp * rect.getHeight());
height = Math.min(pY - rect.y, height);
baseY = pY - height;
if (height > 0) {
tGraphics.fillRect(pX, baseY, dX, height);
}
return pX + dX;
}
/**
* Strand-specific
*
* @param context
* @param pos
* @param rect
* @param maxCount
* @param pY
* @param pX
* @param dX
* @param isPositive
* @param interval
* @return
*/
void drawStrandBar(RenderContext context,
int pos,
Rectangle rect,
double maxCount,
int pY,
int pX,
int dX,
boolean isPositive,
AlignmentCounts interval) {
for (char nucleotide : nucleotides) {
Color c = AlignmentRenderer.nucleotideColors.get(nucleotide);
Graphics2D tGraphics = context.getGraphic2DForColor(c);
int count = isPositive ? interval.getPosCount(pos, (byte) nucleotide) :
interval.getNegCount(pos, (byte) nucleotide);
int height = (int) Math.round(count * rect.getHeight() / maxCount);
height = isPositive ? Math.min(pY - rect.y, height) :
Math.min(rect.y + rect.height - pY, height);
int baseY = (int) (isPositive ? (pY - height) : pY);
if (height > 0) {
tGraphics.fillRect(pX, baseY, dX, height);
}
pY = isPositive ? baseY : baseY + height;
}
}
static float[] colorComps = new float[3];
private Color getShadedColor(int qual, Color backgroundColor, Color color) {
float alpha = 0;
int minQ = prefs.getAsInt(PreferenceManager.SAM_BASE_QUALITY_MIN);
ColorUtilities.getRGBColorComponents(color);
if (qual < minQ) {
alpha = 0.1f;
} else {
int maxQ = prefs.getAsInt(PreferenceManager.SAM_BASE_QUALITY_MAX);
alpha = Math.max(0.1f, Math.min(1.0f, 0.1f + 0.9f * (qual - minQ) / (maxQ - minQ)));
}
// Round alpha to nearest 0.1, for effeciency;
alpha = ((int) (alpha * 10 + 0.5f)) / 10.0f;
if (alpha >= 1) {
return color;
} else {
return ColorUtilities.getCompositeColor(backgroundColor, color, alpha);
}
}
/**
* Override to return a specialized popup menu
*
* @return
*/
@Override
public IGVPopupMenu getPopupMenu(TrackClickEvent te) {
IGVPopupMenu 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();
ArrayList<Track> tmp = new ArrayList();
tmp.add(this);
popupMenu.add(TrackMenuUtils.getChangeTrackHeightItem(tmp));
popupMenu.add(TrackMenuUtils.getTrackRenameItem(tmp));
addCopyDetailsItem(popupMenu, te);
addAutoscaleItem(popupMenu, te.getFrame());
addLogScaleItem(popupMenu);
dataRangeItem = addDataRangeItem(IGV.getMainFrame(), popupMenu, tmp);
this.addSnpTresholdItem(popupMenu);
popupMenu.addSeparator();
addLoadCoverageDataItem(popupMenu);
popupMenu.addSeparator();
popupMenu.add(TrackMenuUtils.getRemoveMenuItem(tmp));
return popupMenu;
}
private void addCopyDetailsItem(IGVPopupMenu popupMenu, TrackClickEvent te) {
JMenuItem copyDetails = new JMenuItem("Copy Details to Clipboard");
copyDetails.setEnabled(false);
if (te.getFrame() != null) {
final String details = getValueStringAt(te.getFrame().getChrName(), te.getChromosomePosition(), te.getMouseEvent().getY(), te.getFrame());
copyDetails.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (details != null) {
String deets = details.replace("<br>", System.getProperty("line.separator"));
StringUtils.copyTextToClipboard(deets);
}
}
});
copyDetails.setEnabled(details != null);
}
popupMenu.add(copyDetails);
}
public static JMenuItem addDataRangeItem(final Frame parentFrame, JPopupMenu menu, final Collection<? extends Track> selectedTracks) {
JMenuItem maxValItem = new JMenuItem("Set Data Range");
maxValItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (selectedTracks.size() > 0) {
DataRange prevAxisDefinition = selectedTracks.iterator().next().getDataRange();
DataRangeDialog dlg = new DataRangeDialog(parentFrame, prevAxisDefinition);
dlg.setHideMid(true);
dlg.setVisible(true);
if (!dlg.isCanceled()) {
float min = Math.min(dlg.getMin(), dlg.getMax());
float max = Math.max(dlg.getMin(), dlg.getMax());
float mid = dlg.getBase();
if (mid < min) mid = min;
else if (mid > max) mid = max;
DataRange dataRange = new DataRange(min, mid, max);
dataRange.setType(dlg.getDataRangeType());
for (Track track : selectedTracks) {
track.setDataRange(dataRange);
track.setAutoScale(false);
}
parentFrame.repaint();
}
}
}
});
if (menu != null) menu.add(maxValItem);
return maxValItem;
}
public JMenuItem addSnpTresholdItem(JPopupMenu menu) {
JMenuItem maxValItem = new JMenuItem("Set allele frequency threshold...");
maxValItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String value = JOptionPane.showInputDialog("Allele frequency threshold: ", Float.valueOf(snpThreshold));
if (value == null) {
return;
}
try {
float tmp = Float.parseFloat(value);
snpThreshold = tmp;
IGV.getInstance().repaintDataPanels();
} catch (Exception exc) {
//log
}
}
});
menu.add(maxValItem);
return maxValItem;
}
public void addLoadCoverageDataItem(JPopupMenu menu) {
// Change track height by attribute
final JMenuItem item = new JCheckBoxMenuItem("Load coverage data...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final PreferenceManager prefs = PreferenceManager.getInstance();
File initDirectory = prefs.getLastTrackDirectory();
File file = FileDialogUtils.chooseFile("Select coverage file", initDirectory, FileDialog.LOAD);
if (file != null) {
prefs.setLastTrackDirectory(file.getParentFile());
String path = file.getAbsolutePath();
if (path.endsWith(".tdf") || path.endsWith(".tdf")) {
TDFReader reader = TDFReader.getReader(file.getAbsolutePath());
TDFDataSource ds = new TDFDataSource(reader, 0, getName() + " coverage", genome);
setDataSource(ds);
IGV.getInstance().repaintDataPanels();
} else if (path.endsWith(".counts")) {
CoverageDataSource ds = new GobyCountArchiveDataSource(file);
setDataSource(ds);
IGV.getInstance().repaintDataPanels();
} else {
MessageUtils.showMessage("Coverage data must be in .tdf format");
}
}
}
});
menu.add(item);
}
public void addAutoscaleItem(JPopupMenu menu,final ReferenceFrame frame) {
// Change track height by attribute
autoscaleItem = new JCheckBoxMenuItem("Autoscale");
autoscaleItem.setSelected(autoScale);
autoscaleItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
autoScale = autoscaleItem.isSelected();
dataRangeItem.setEnabled(!autoScale);
if (autoScale) {
rescale(frame);
}
IGV.getInstance().repaintDataPanels();
}
});
menu.add(autoscaleItem);
}
public void addLogScaleItem(JPopupMenu menu) {
// Change track height by attribute
final DataRange dataRange = getDataRange();
final JCheckBoxMenuItem logScaleItem = new JCheckBoxMenuItem("Log scale");
final boolean logScale = dataRange.getType() == DataRange.Type.LOG;
logScaleItem.setSelected(logScale);
logScaleItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DataRange.Type scaleType = logScaleItem.isSelected() ?
DataRange.Type.LOG :
DataRange.Type.LINEAR;
dataRange.setType(scaleType);
IGV.getInstance().repaintDataPanels();
}
});
menu.add(logScaleItem);
}
@SubtlyImportant
private static CoverageTrack getNextTrack() {
return (CoverageTrack) IGVSessionReader.getNextTrack();
}
public void setGlobalAutoScale(boolean globalAutoScale) {
this.globalAutoScale = globalAutoScale;
}
}