All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.graphics.Gene2D Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.graphics;


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.util.ArrayList;
import java.util.List;

import com.hfg.bio.seq.Exon;
import com.hfg.bio.Strand;
import com.hfg.bio.seq.SeqMappingCoverage;
import com.hfg.bio.taxonomy.NCBITaxon;
import com.hfg.html.Link;
import com.hfg.svg.SvgNode;
import com.hfg.svg.SvgGroup;
import com.hfg.svg.SvgRect;
import com.hfg.svg.SvgText;
import com.hfg.util.collection.CollectionUtil;
import com.hfg.util.StringBuilderPlus;
import com.hfg.javascript.TooltipJS;

//------------------------------------------------------------------------------
/**
 Simple 2D representation of a gene.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class Gene2D extends Rectangle implements Comparable { //########################################################################## // PRIVATE FIELDS //########################################################################## private String mId; private String mDescription; private List mURLs; private int mStartLocation; private int mEndLocation; private Strand mStrand; private List mExons; private NCBITaxon mSpecies; private SeqMappingCoverage mSeqMappingCoverage; private int mDisplayStart; private int mDisplayEnd; private boolean mInDisplayRegion; private boolean mShowId = true; private int mLabelWidthInPixels = -1; private Color mColor; // private Font mLabelFont = new Font("Monospaced", Font.PLAIN, 9); private Font mLabelFont = Font.decode("Courier-PLAIN-9"); private double mXScalingFactor; private int mHeightInPixels = 10; private static Color DEFAULT_COLOR = Color.black; private static FontRenderContext sFRC; static { Frame frame = new Frame(); frame.addNotify(); Image image =frame.createImage(1, 1); sFRC = ((Graphics2D) image.getGraphics()).getFontRenderContext(); } //########################################################################## // CONSTRUCTORS //########################################################################## //-------------------------------------------------------------------------- public Gene2D() { } //########################################################################## // PUBLIC METHODS //########################################################################## //-------------------------------------------------------------------------- public void addExon(Exon inValue) { if (null == mExons) { mExons = new ArrayList<>(); } mExons.add(inValue); if (mStrand == null && inValue.getStrand() != null) { mStrand = inValue.getStrand(); } if (mStartLocation == 0 || inValue.getLeft() < mStartLocation) { mStartLocation = inValue.getLeft(); } if (mEndLocation == 0 || inValue.getRight() > mEndLocation) { mEndLocation = inValue.getRight(); } } //-------------------------------------------------------------------------- public List getExons() { return mExons; } //-------------------------------------------------------------------------- public void setId(String inValue) { mId = inValue; mLabelWidthInPixels = -1; } //-------------------------------------------------------------------------- public String getId() { return mId; } //-------------------------------------------------------------------------- public void setDescription(String inValue) { mDescription = inValue; } //-------------------------------------------------------------------------- public String getDescription() { return mDescription; } //-------------------------------------------------------------------------- public void setSeqMappingCoverage(SeqMappingCoverage inValue) { mSeqMappingCoverage = inValue; } //-------------------------------------------------------------------------- public SeqMappingCoverage getSeqMappingCoverage() { return mSeqMappingCoverage; } //-------------------------------------------------------------------------- public void setSpecies(NCBITaxon inValue) { mSpecies = inValue; } //-------------------------------------------------------------------------- public NCBITaxon getSpecies() { return mSpecies; } //-------------------------------------------------------------------------- /** Add a URL to the gene. If more than one URL is defined, a popup menu will be shown. @param inValue the link to associate with the gene */ public void addURL(Link inValue) { if (null == mURLs) { mURLs = new ArrayList<>(2); } mURLs.add(inValue); } //-------------------------------------------------------------------------- public List getURLs() { return mURLs; } //-------------------------------------------------------------------------- /** Basepair location of the start of the gene. @return the 1-based location */ public int getStartLocation() { return mStartLocation; } //-------------------------------------------------------------------------- public void setStartLocation(int inValue) { mStartLocation = inValue; } //-------------------------------------------------------------------------- public int getEndLocation() { return mEndLocation; } //-------------------------------------------------------------------------- public void setEndLocation(int inValue) { mEndLocation = inValue; } //-------------------------------------------------------------------------- /** The leftmost basepair of the gene (the start location if the gene is on the forward strand or the end location if the gene is on the reverse strand). @return the 1-based left location */ public int getLeft() { return Math.min(mStartLocation, mEndLocation); } //-------------------------------------------------------------------------- /** The rightmost basepair of the gene (the end location if the gene is on the forward strand or the start location if the gene is on the reverse strand). @return the 1-based right location */ public int getRight() { return Math.max(mStartLocation, mEndLocation); } //-------------------------------------------------------------------------- public Strand getStrand() { return mStrand; } //-------------------------------------------------------------------------- public void setStrand(Strand inValue) { mStrand = inValue; } //-------------------------------------------------------------------------- public void setColor(Color inValue) { mColor = inValue; } //-------------------------------------------------------------------------- public Color getColor() { return mColor; } //-------------------------------------------------------------------------- public void setLabelFont(Font inValue) { mLabelFont = inValue; } //-------------------------------------------------------------------------- public void setXScalingFactor(double inValue) { mXScalingFactor = inValue; } //-------------------------------------------------------------------------- public void setShowId(boolean inValue) { mShowId = inValue; } //-------------------------------------------------------------------------- public boolean getShowId() { return mShowId; } //-------------------------------------------------------------------------- public void setDisplayRegion(int inDisplayStart, int inDisplayEnd) { mDisplayStart = Math.max(getLeft(), inDisplayStart); mDisplayEnd = Math.min(getRight(), inDisplayEnd); mInDisplayRegion = (mDisplayEnd >= mDisplayStart ? true : false); } //-------------------------------------------------------------------------- public boolean inDisplayRegion() { return mInDisplayRegion; } //-------------------------------------------------------------------------- public SvgNode toSVG() { SvgGroup group = new SvgGroup(); if (mInDisplayRegion) { Color color = (mColor != null ? mColor : DEFAULT_COLOR); // Draw the gene line. int width = getScaledWidthInPixels(mDisplayStart, mDisplayEnd); group.addRect(new Rectangle(new Point(0, mHeightInPixels/2), new Dimension(width, 1))).setFill(color); if (mShowId && mId != null) { Rectangle textBoundBox = TextUtil.getStringRect(mId, mLabelFont); SvgText label = group.addText(mId, mLabelFont, new Point(width + 1, (int) (mHeightInPixels/2f + textBoundBox.getHeight()/2f) - 2)); TooltipJS tooltip = new TooltipJS(); tooltip.addTooltip(label, getTooltipContent()); } List exons = drawExons(); if (CollectionUtil.hasValues(exons)) { group.addSubtags(exons); } TooltipJS tooltip = new TooltipJS(); tooltip.addTooltip(group, getTooltipContent()); } return group; } //-------------------------------------------------------------------------- public void draw(Graphics2D g2) { if (mInDisplayRegion) { // Save settings Paint origPaint = g2.getPaint(); Font origFont = g2.getFont(); Color color = (mColor != null ? mColor : DEFAULT_COLOR); g2.setPaint(color); // Draw the gene line. // System.out.println(getId() + ": " + mDisplayStart + "-" + mDisplayEnd);///////////////////////// int width = getScaledWidthInPixels(mDisplayStart, mDisplayEnd); g2.fillRect(0, mHeightInPixels/2, width, 1); if (mShowId && mId != null) { FontRenderContext frc = g2.getFontRenderContext(); TextLayout layout = new TextLayout(mId, mLabelFont, frc); g2.drawString(mId, width + 1, (int) (mHeightInPixels/2 + layout.getBounds().getHeight()/2)); } drawExons(g2); // Restore settings g2.setPaint(origPaint); g2.setFont(origFont); } } //-------------------------------------------------------------------------- public int getScaledWidthInPixels() { return getScaledWidthInPixels(getDisplayBoundedValue(getLeft()), getDisplayBoundedValue(getRight())); } //-------------------------------------------------------------------------- public void setHeightInPixels(int inValue) { mHeightInPixels = inValue; } //-------------------------------------------------------------------------- public int getHeightInPixels() { return mHeightInPixels; } //-------------------------------------------------------------------------- public int getLabelWidthInPixels() { if (mLabelWidthInPixels == -1) { if (mId != null && mId.length() > 0) { TextLayout layout = new TextLayout(mId, mLabelFont, sFRC); mLabelWidthInPixels = (int) layout.getBounds().getWidth() + 1; } else { mLabelWidthInPixels = 0; } } return mLabelWidthInPixels; } //-------------------------------------------------------------------------- public String getTooltipContent() { StringBuilderPlus text = new StringBuilderPlus().setDelimiter("
"); if (getId() != null && (null == getDescription() || getDescription().indexOf(getId()) < 0)) { text.append(getId()); } if (getDescription() != null) { text.delimitedAppend(getDescription()); } if (mSeqMappingCoverage != null) { text.delimitedAppend("Mapping: "); if (mSeqMappingCoverage.getMappedLength() != null) { text.append(mSeqMappingCoverage.getMappedLength()); } else { text.append("?"); } text.append("/"); if (mSeqMappingCoverage.getQueryLength() != null) { text.append(mSeqMappingCoverage.getQueryLength()); } else { text.append("?"); } if (mSeqMappingCoverage.getPercentIdentity() != null) { text.append(String.format(" (%d%% identity)", mSeqMappingCoverage.getPercentIdentity().intValue())); } text.append(""); } if (getSpecies() != null) { text.delimitedAppend(""); text.append(getSpecies().getScientificName()); text.append(""); } text.delimitedAppend(""); if (getStrand() != null) { text.append("Strand: ("); text.append(getStrand().getSymbol()); text.append(") "); } text.append("bp.: "); text.append(getLeft()); text.append(getLeft() != getRight() ?" - " + getRight() : ""); text.append(""); return text.toString(); } //-------------------------------------------------------------------------- @Override public boolean equals(Object o2) { return (o2 instanceof Gene2D && compareTo((Gene2D)o2) == 0 ? true : false); } //-------------------------------------------------------------------------- public int compareTo(Gene2D gene2) { int returnValue = 0; if (this != gene2) { if (getLeft() > gene2.getLeft()) { returnValue = 1; } else if (getLeft() < gene2.getLeft()) { returnValue = -1; } else { if (getRight() > gene2.getRight()) { returnValue = 1; } else if (getRight() < gene2.getRight()) { returnValue = -1; } else { // Somewhat arbitrary but this method will really only need to // be called to order by position. Returning 0 when the objects // are not the same can screw up hashes. returnValue = 1; } } } return returnValue; } //########################################################################## // PRIVATE METHODS //########################################################################## //-------------------------------------------------------------------------- private boolean isExonInDisplayRegion(Exon inExon) { boolean returnValue = false; if (inExon.getRight() >= mDisplayStart && inExon.getLeft() <= mDisplayEnd) { returnValue = true; } return returnValue; } //-------------------------------------------------------------------------- private void drawExons(Graphics2D g2) { if (mExons != null) { // Save settings Paint origPaint = g2.getPaint(); for (Exon exon : mExons) { if (isExonInDisplayRegion(exon)) { // Calculate exon location int xOffset = getBoundedAndScaledLocation(exon.getLeft()); // Draw the exon int width = getScaledWidthInPixels(getDisplayBoundedValue(exon.getLeft()), getDisplayBoundedValue(exon.getRight())); if (exon.getColor() != null) { g2.setPaint(exon.getColor()); } g2.fillRect(xOffset, 0, width, mHeightInPixels); if (exon.getColor() != null) { // Restore settings g2.setPaint(origPaint); } } } } } //-------------------------------------------------------------------------- private List drawExons() { List exons = null; if (mExons != null) { exons = new ArrayList<>(mExons.size()); for (Exon exon : mExons) { if (isExonInDisplayRegion(exon)) { // Calculate exon location int xOffset = getBoundedAndScaledLocation(exon.getLeft()); // Draw the exon int width = getScaledWidthInPixels(getDisplayBoundedValue(exon.getLeft()), getDisplayBoundedValue(exon.getRight())); SvgRect svgExon = new SvgRect(new Rectangle(new Point(xOffset, 0), new Dimension(width, mHeightInPixels))); Color color = (mColor != null ? mColor : DEFAULT_COLOR); if (exon.getColor() != null) { color = exon.getColor(); } svgExon.setFill(color); exons.add(svgExon); } } } return exons; } //-------------------------------------------------------------------------- private int getScaledWidthInPixels(int inStart, int inEnd) { int leftPixel = (int) (inStart * mXScalingFactor); int rightPixel = (int) (inEnd * mXScalingFactor); int width = rightPixel - leftPixel + 1; // System.out.println("Exon: " + inStart + "-" + inEnd + " " + leftPixel + "-" + rightPixel + " " + mXScalingFactor + " (" + width + ")");///////////////////////// // int width = Math.abs((int) ((inEnd - inStart + 1) * mXScalingFactor)); // Minimum width of 1 return (0 >= width ? 1 : width); } //-------------------------------------------------------------------------- private int getBoundedAndScaledLocation(int inValue) { int bound = (int) (getDisplayBoundedValue(inValue) * mXScalingFactor); int start = (int) (mDisplayStart * mXScalingFactor); return bound - start; // return (int)((getDisplayBoundedValue(inValue) - mDisplayStart) * mXScalingFactor); } //-------------------------------------------------------------------------- private int getDisplayBoundedValue(int inValue) { int value = inValue; if (value < mDisplayStart) { value = mDisplayStart; } else if (value > mDisplayEnd) { value = mDisplayEnd; } return value; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy