net.maizegenetics.analysis.popgen.LinkageDisequilibriumComponent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tassel Show documentation
Show all versions of tassel Show documentation
TASSEL is a software package to evaluate traits associations, evolutionary patterns, and linkage
disequilibrium.
// LinkageDisequilibriumComponent.java
//
// (c) 1999-2001 PAL Development Core Team
//
// This package may be distributed under the
// terms of the Lesser GNU General Public License (LGPL)
package net.maizegenetics.analysis.popgen;
import net.maizegenetics.dna.snp.GenotypeTable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
/**
* An AWT Component for displaying information on linkage disequilibrium.
*
* Nice schematics are produced if an annotation alignment is used to construct
* LinkageDisequilibrium. It can portray things both on the gene and chromosomal
* scale.
*
*
* @author Ed Buckler
* @version $Id: LinkageDisequilibriumComponent.java
*/
public class LinkageDisequilibriumComponent extends JComponent {
public final static int P_VALUE = 0;
public final static int DPRIME = 1;
public final static int RSQUARE = 2;
double minimumChromosomeLength = 10;
LinkageDisequilibrium theLD;
GenotypeTable theAA;
boolean includeBlockSchematic, chromosomalScale;
boolean includeLabels = true;
int totalVariableSites, totalLoci, totalChromosomes, totalIntervals, totalBlocks;
double[] startPos, endPos; //These are the relative positions of the polymorphisms
double[] blockBeginPos, blockEndPos;
String[] blockNames;
int[] xPos, yPos, xEndPos; //these hold positions of the upper left corners for each site
int[] blockBeginX, blockEndX;//These are the absolute positions of the genes & chromosomes
int ih, iw;
double[] blockStart, blockEnd;
//this will range from 0 to 1
String upperLabel, lowerLabel;
double[][] diseq;
Color theColor = new Color(0, 0, 0);
int distanceBetweenGraphAndGene = 40;
int hoff = 70, h2off = 70, voff = 20;
boolean probability = true, upperProb = false, lowerProb = true;
//viewer attribute variables
int myWindowSize;
int myWindowX;
int myWindowY;
//stat and end coordinates for LD plot including chromosome jumps
int myXStart;
int myXEnd;
int myYStart;
int myYEnd;
//used to correct for chromosome jumps when accessing indexed info from LD or alignment
int[] jump;
public LinkageDisequilibriumComponent(LinkageDisequilibrium theLD, boolean includeBlockSchematic, boolean chromosomalScale, int windowSize, int windowX, int windowY) {
this.theLD = theLD;
theAA = theLD.getAlignment();
this.includeBlockSchematic = includeBlockSchematic;
this.chromosomalScale = chromosomalScale;
myWindowSize = windowSize;
myWindowX = windowX;
myWindowY = windowY;
totalVariableSites = theLD.getSiteCount();
this.diseq = new double[windowSize][windowSize];
setXStart();
setYStart();
jump = new int[totalVariableSites+theAA.numChromosomes()-1];
String locus = theAA.chromosomeName(0);
int jumpValue = 0;
for (int i = 0; i< jump.length; i++) {
if (!locus.equals(theAA.chromosomeName(i+jumpValue))) {
locus = theAA.chromosomeName(i+jumpValue);
jumpValue--;
jump[i] = 1;
} else {
jump[i] = jumpValue;
}
}
setUpperCorner(RSQUARE);
setLowerCorner(P_VALUE);
if (theAA != null) {
countGenesAndChromosomes();
calculateStartAndEndPositions();
} else {
includeBlockSchematic = false;
}
xPos = new int[windowSize + 1];
yPos = new int[windowSize + 1];
xEndPos = new int[windowSize + 1];
setToolTipText("");
try {
jbInit();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* This sets the X start and end positions
*/
public void setXStart() {
myXStart = (int)Math.floor(myWindowX-myWindowSize/2.0);
myXEnd = myXStart + myWindowSize;
}
/**
* This sets the Y start and end positions
*/
public void setYStart() {
myYStart = (int)Math.floor(myWindowY-myWindowSize/2.0);
myYEnd = myYStart + myWindowSize;
}
/**
* This sets a new viewable size
*/
public void setWindowSize(int newSize, int newX, int newY, int ldMeasureLower, int ldMeasureUpper) {
myWindowSize = newSize;
myWindowX = newX;
myWindowY = newY;
diseq = new double[myWindowSize][myWindowSize];
xPos = new int[myWindowSize + 1];
yPos = new int[myWindowSize + 1];
xEndPos = new int[myWindowSize + 1];
setXStart();
setYStart();
setLowerCorner(ldMeasureLower);
setUpperCorner(ldMeasureUpper);
if (theAA != null) {
countGenesAndChromosomes();
calculateStartAndEndPositions();
}
}
/**
* This sets a new X position
*/
public void setWindowX(int newX, int ldMeasureLower, int ldMeasureUpper) {
myWindowX = newX;
setXStart();
calculateStartAndEndPositions();
setLowerCorner(ldMeasureLower);
setUpperCorner(ldMeasureUpper);
}
/**
* This sets a new Y position
*/
public void setWindowY(int newY, int ldMeasureLower, int ldMeasureUpper) {
myWindowY = newY;
setYStart();
calculateStartAndEndPositions();
setLowerCorner(ldMeasureLower);
setUpperCorner(ldMeasureUpper);
}
/**
* This determines what is displayed in the lower left corner.
* Options are: P_VALUE, DPRIME, and RSQUARE
*/
public void setLowerCorner(int ldMeasure) {
for (int r = 0; r < myWindowSize; r++) {
if (jump[r+myXStart] != 1) {
for (int c = Math.max(r+myXStart-myYStart, 0); c < myWindowSize; c++) {
if (jump[c+myYStart] != 1) {
switch (ldMeasure) {
case P_VALUE: {
diseq[r][c] = theLD.getPVal(c+myYStart+jump[c+myYStart], r+myXStart+jump[r+myXStart]);
lowerLabel = "P value";
break;
}
case DPRIME: {
diseq[r][c] = theLD.getDPrime(c+myYStart+jump[c+myYStart], r+myXStart+jump[r+myXStart]);
lowerLabel = "D'";
break;
}
case RSQUARE: {
diseq[r][c] = theLD.getRSqr(c+myYStart+jump[c+myYStart], r+myXStart+jump[r+myXStart]);
lowerLabel = "R^2";
break;
}
}
}
}
}
}
lowerProb = (ldMeasure == P_VALUE) ? true : false;
}
/**
* This determines what is displayed in the upper right corner.
* Options are: P_VALUE, DPRIME, and RSQUARE
*/
public void setUpperCorner(int ldMeasure) {
for (int c = 0; c < myWindowSize; c++) {
if (jump[c+myYStart] != 1) {
for (int r = Math.max(c+myYStart-myXStart, 0); r < myWindowSize; r++) {
if (jump[r+myXStart] != 1) {
switch (ldMeasure) {
case P_VALUE: {
diseq[r][c] = theLD.getPVal(r+myXStart+jump[r+myXStart], c+myYStart+jump[c+myYStart]);
upperLabel = "P value";
break;
}
case DPRIME: {
diseq[r][c] = theLD.getDPrime(r+myXStart+jump[r+myXStart], c+myYStart+jump[c+myYStart]);
upperLabel = "D'";
break;
}
case RSQUARE: {
diseq[r][c] = theLD.getRSqr(r+myXStart+jump[r+myXStart], c+myYStart+jump[c+myYStart]);
upperLabel = "R squared";
break;
}
}
}
}
}
}
upperProb = (ldMeasure == P_VALUE) ? true : false;
}
/**
* This sets the scale of the LD view, either sites are organized by chromosomes if
* chromosomalScale is true, otherwise they are organized by genes
*/
public void setScaleOfView(boolean chromosomalScale) {
this.chromosomalScale = chromosomalScale;
countGenesAndChromosomes();
calculateStartAndEndPositions();
}
/**
* This sets whether a schematic is displayed. If true a schematic of genes or
* chromosomes is displayed, otherwise no schematic is displayed
*/
public void setShowSchematic(boolean includeBlockSchematic) {
if (theAA == null) {
return; //if there is no annotation don't produce the schematic
}
this.includeBlockSchematic = includeBlockSchematic;
countGenesAndChromosomes();
calculateStartAndEndPositions();
}
public void setShowLabels(boolean includeLabels) {
if (this.includeLabels == includeLabels) {
return;
}
this.includeLabels = includeLabels;
countGenesAndChromosomes();
calculateStartAndEndPositions();
}
/**
* this counts the number of separate blocks
* if on chromosomal scale then chromosomes are counted otherwise only loci are counted
* It then deteremines the total span in terms of cM or bases depending on scale
*/
private void countGenesAndChromosomes() {
totalLoci = totalChromosomes = 0;
String currLocus = "";
for (int r = 0; r < totalVariableSites; r++)
{
if (!currLocus.equals(theAA.chromosomeName(r))) {
totalLoci++;
currLocus = theAA.chromosomeName(r);
}
}
//the number of separate totalBlocks
totalBlocks = (chromosomalScale) ? totalChromosomes : totalLoci;
if (totalBlocks == 0) {
totalBlocks = 1;
}
blockStart = new double[totalBlocks];
blockEnd = new double[totalBlocks];
blockNames = new String[totalBlocks];
for (int i = 0; i < totalChromosomes; i++) {
blockStart[i] = 999999;
blockEnd[i] = -999999;
}
int c = -1;
currLocus = "unknown locus";
for (int r = 0; r < totalVariableSites; r++) {
if (!currLocus.equals(theAA.chromosomeName(r))) {
c++;
currLocus = theAA.chromosomeName(r);
blockNames[c] = currLocus;
}
if (blockStart[c] > theAA.chromosomalPosition(r)) {
blockStart[c] = theAA.chromosomalPosition(r);
}
if (blockEnd[c] < theAA.chromosomalPosition(r)) {
blockEnd[c] = theAA.chromosomalPosition(r);
}
}
for (int i = 0; i < totalBlocks; i++) {
if ((chromosomalScale) && ((blockEnd[i] - blockStart[i]) < minimumChromosomeLength)) {
blockEnd[i] = blockStart[i] + minimumChromosomeLength;
} else if ((blockEnd[i] - blockStart[i]) < 1) {
blockEnd[i] = blockStart[i] + 1;
}
}
}
/**
* this determines to relative positions of the sites and cartoons (everything ranges from 0..1)
*
*/
void calculateStartAndEndPositions() {
//This will determine were all the relative positions of the sites go
double proportionPerPolymorphism;// proportionPerUnit = 0.0f;
if (includeBlockSchematic) {
proportionPerPolymorphism = 1 / (double) myWindowSize;
blockBeginPos = new double[totalBlocks]; //These hold the start and end points of the genes
blockEndPos = new double[totalBlocks];
} else {
totalIntervals = myWindowSize;
proportionPerPolymorphism = 1 / (double) totalIntervals;
}
startPos = new double[myWindowSize];
endPos = new double[myWindowSize];
startPos[0] = 0;
endPos[0] = 0;
for (int r = 0; r < myWindowSize; r++) {
startPos[r] = r * proportionPerPolymorphism;
} //end of going through sites
if (includeBlockSchematic) {
for (int b = 0; b < totalBlocks; b++) {
blockBeginPos[b] = b / (double)totalBlocks;
blockEndPos[b] = (b + 1) / (double)totalBlocks;
}
int currB = 0;
for (int i = 1; i < myXStart; i++) {
if (!theAA.chromosomeName(i+jump[i]).equals(theAA.chromosomeName(i+jump[i] - 1))) {
currB++;
}
}
endPos[0] = blockBeginPos[currB] + (theAA.chromosomalPosition(myXStart+jump[myXStart]) - blockStart[currB]) / (blockEnd[currB] - blockStart[currB]) / totalBlocks;
for (int r = myXStart+1; r < myXEnd; r++) {
if (!theAA.chromosomeName(r+jump[r]).equals(theAA.chromosomeName(r+jump[r] - 1))) {
currB++;
}
endPos[r-myXStart] = blockBeginPos[currB] + (theAA.chromosomalPosition(r+jump[r]) - blockStart[currB]) / (blockEnd[currB] - blockStart[currB]) / totalBlocks;
}
}
}
private void jbInit() throws Exception {
this.setBackground(Color.red);
this.setSize(400, 400);
}
private Color getMagnitudeColor(int r, int c) {
if (r + myWindowX == c + myWindowY) {
return theColor.getHSBColor(0.999f, (float) diseq[r][c], 1f);
}
if (Double.isNaN(diseq[r][c])) {
return theColor.lightGray;
}
if (diseq[r][c] > 0.999) {
return theColor.getHSBColor(1f, 1f, 1f);
}
if (diseq[r][c] < -998.0) {
return theColor.lightGray;
}
if ((((float) diseq[r][c]) + (1.0000f - ((float) diseq[r][c])) / 2) < 0.52f) {
return theColor.getHSBColor(((float) diseq[r][c]) + (1.0000f - ((float) diseq[r][c])) / 2 - .5f, ((float) diseq[r][c]) + (1.0000f - ((float) diseq[r][c])) / 2 - .5f, 1f);
} else {
return theColor.getHSBColor(((float) diseq[r][c]) + (1.0000f - ((float) diseq[r][c])) / 2, ((float) diseq[r][c]) + (1.0000f - ((float) diseq[r][c])) / 2, 1f);
}
}
private Color getProbabilityColor(int r, int c) {
double p1 = 0.01, p2 = 0.001, p3 = 0.0001;
if (Double.isNaN(diseq[r][c])) {
return theColor.lightGray;
}
if (diseq[r][c] < -998.0) {
return theColor.lightGray;
}
if (diseq[r][c] > p1) {
return theColor.white;
}
if (diseq[r][c] > p2) {
return theColor.blue;
}
if (diseq[r][c] > p3) {
return theColor.green;
}
return theColor.red;
}
private void addPolymorphismLabels(Graphics g, int ih) {
String s;
g.setFont(new java.awt.Font("Dialog", 0, 9));
g.setColor(theColor.black);
for (int c = myYStart; c < myYEnd; c++) {
if (jump[c] != 1) {
s = theAA.chromosomeName(c+jump[c]) + "s" + theAA.chromosomalPosition(c+jump[c]);
} else {
s = "";
}
g.drawString(s, 4, yPos[c-myYStart] + ih - 1);
}
}
/**
* This converts all those relative positions to real coordinates based on the size of the component
*/
private void calculateCoordinates(Graphics gr) {
Dimension d = this.getSize();
double iwf, ihf, xSize, ySize;
ySize = d.height - voff - distanceBetweenGraphAndGene;
ihf = ySize / (double) myWindowSize;
xSize = d.width - hoff - h2off;
iwf = xSize / (double) myWindowSize;
ih = (int) Math.round(ihf);
iw = (int) Math.round(iwf);
for (int r = 0; r < myWindowSize; r++) {
xPos[r] = (int) ((startPos[r] * xSize) + (double) hoff);
yPos[r] = (int) ((startPos[r] * ySize) + (double) voff);
} //end of going through sites
xPos[myWindowSize] = (int) d.width - h2off;
yPos[myWindowSize] = (int) ySize + voff;
if (includeBlockSchematic) {
for (int r = 0; r < myWindowSize; r++) {
xEndPos[r] = (int) Math.round((endPos[r] * xSize) + hoff);
} //end of going through sites
blockBeginX = new int[totalBlocks];
blockEndX = new int[totalBlocks];
for (int b = 0; b < totalBlocks; b++) {
blockBeginX[b] = (int) Math.round((blockBeginPos[b] * xSize) + hoff);
blockEndX[b] = (int) Math.round((blockEndPos[b] * xSize) + hoff);
}
}
}
protected void paintComponent(Graphics g) {
if (diseq == null) {
return;
}
// super.paintComponent(g);
Dimension d = this.getSize();
calculateCoordinates(g);
g.setColor(theColor.white);
g.fillRect(0, 0, d.width, d.height);
g.setColor(theColor.darkGray);
g.fillRect(xPos[0], yPos[0], xPos[myWindowSize] - xPos[0], yPos[myWindowSize] - yPos[0] + 2);
//checks to see if a jump has occured
for (int r = myXStart; r < myXEnd; r++) {
if (jump[r] == 1) {
g.setColor(theColor.darkGray);
for (int c = myYStart; c < myYEnd; c++) {
g.fillRect(xPos[r-myXStart], yPos[c-myYStart], iw + 1, ih + 1);
}
} else {
for (int c = myYStart; c < myYEnd; c++) {
if (jump[c] == 1){
g.setColor(theColor.darkGray);
} else if (((c+jump[c] < r+jump[r]) && (upperProb == true)) || ((c+jump[c] > r+jump[r]) && (lowerProb == true))) {
g.setColor(getProbabilityColor(r-myXStart, c-myYStart));
} else if (r == c) {
g.setColor(theColor.black);
} else {
g.setColor(getMagnitudeColor(r-myXStart, c-myYStart));
}
g.fillRect(xPos[r-myXStart], yPos[c-myYStart], iw + 1, ih + 1);
}
}
}
// Removed grid lines because the cover too much
// on large graphs. -terryc
/*
g.setColor(theColor.darkGray);
for(int r=0; r0.01", xStart + barWidth + 5, currY + 10);
currY += yInc;
g.setColor(theColor.blue);
g.fillRect(xStart, currY, barWidth, yInc);
g.setColor(Color.black);
g.drawRect(xStart, currY, barWidth, yInc);
g.drawString("<0.01", xStart + barWidth + 5, currY + 10);
currY += yInc;
g.setColor(theColor.green);
g.fillRect(xStart, currY, barWidth, yInc);
g.setColor(Color.black);
g.drawRect(xStart, currY, barWidth, yInc);
g.drawString("<0.001", xStart + barWidth + 5, currY + 10);
currY += yInc;
g.setColor(theColor.red);
g.fillRect(xStart, currY, barWidth, yInc);
g.setColor(Color.black);
g.drawRect(xStart, currY, barWidth, yInc);
g.drawString("<0.0001", xStart + barWidth + 5, currY + 10);
} else {
yInc = (yEnd - yStart) / 11;
dF = new DecimalFormat("0.00");
for (double d = 1.0000f; d >= 0.5; d -= 0.05) {
g.setColor(theColor.getHSBColor((float) d, (float) d, 1f));
g.fillRect(xStart, currY, barWidth, yInc);
g.setColor(Color.black);
g.drawRect(xStart, currY, barWidth, yInc);
g.drawString(dF.format(d - (1.0001f - d)), xStart + barWidth + 5, currY + 10);
currY += yInc;
}
g.setColor(theColor.getHSBColor((float) 0, (float) 0, 1f));
g.fillRect(xStart, currY, barWidth, yInc);
g.setColor(Color.black);
g.drawRect(xStart, currY, barWidth, yInc);
g.drawString(dF.format(0.00), xStart + barWidth + 5, currY + 10);
}
}
private void addGenePicture(Graphics g, int ih, int iw) {
//This will add the gene picture to the left of the polymorphisms
int yOfLinkBlock, yOfGene, yOfGeneLabel;//,totalBases,spacer, cpos;
int halfIW = iw / 2;
// MultiAlleleSiteCharacteristic theMSC, lastMSC;
Dimension d = this.getSize();
yOfLinkBlock = yPos[myWindowSize];
yOfGene = yOfLinkBlock + (distanceBetweenGraphAndGene / 2);
yOfGeneLabel = yOfLinkBlock + (int) (0.8f * (double) distanceBetweenGraphAndGene);
for (int r = 0; r < myWindowSize; r++) {
if (jump[r+myXStart] != 1) {
g.drawLine(xPos[r] + halfIW, yOfLinkBlock + 1, xEndPos[r], yOfGene);
}
} //end of going through sites
for (int b = 0; b < totalBlocks; b++) {
g.setColor(iterColor(b));
g.drawLine(blockBeginX[b], yOfGene, blockEndX[b], yOfGene);
g.drawLine(blockBeginX[b], yOfGene + 1, blockEndX[b], yOfGene + 1);
g.drawString(blockNames[b], blockBeginX[b], yOfGeneLabel);
}
}
private Color iterColor(int iter) {
Color newColor;
if (iter % 5 == 0) {
newColor = theColor.blue;
} else if (iter % 5 == 1) {
newColor = theColor.red;
} else if (iter % 5 == 2) {
newColor = theColor.green;
} else if (iter % 5 == 3) {
newColor = theColor.cyan;
} else {
newColor = theColor.orange;
}
return newColor;
}
public String getToolTipText(MouseEvent e) {
Point graphPoint = getLocationOnScreen();
Point mousePoint = e.getLocationOnScreen();
double graphX = graphPoint.getX();
double graphY = graphPoint.getY();
double mouseX = mousePoint.getX() - graphX;
double mouseY = mousePoint.getY() - graphY;
DecimalFormat format = new DecimalFormat("0.###E0");
for (int r = myXStart; r < myXEnd; r++) {
if (jump[r] != 1 && mouseX > xPos[r-myXStart] && mouseX < xPos[r-myXStart+1]) {
for (int c = myYStart; c < myYEnd; c++) {
if (jump[c] != 1 && mouseY > yPos[c-myYStart] && mouseY < yPos[c-myYStart+1]) {
return theAA.siteName(r+jump[r]) + ": " + theAA.chromosomalPosition(r+jump[r]) + ", " + theAA.siteName(c+jump[c]) + ": " + theAA.chromosomalPosition(c+jump[c]) + ", Value: " + format.format(diseq[r-myXStart][c-myYStart]);
}
}
}
}
return null;
}
public void setGraphSize(int graphX, int graphY) {
setPreferredSize(new Dimension(graphX, graphY));
setSize(new Dimension(graphX, graphY));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy