package contextViewer;
import genomeObjects.AnnotatedGenome;
import genomeObjects.CSDisplayData;
import genomeObjects.GenomicElement;
import genomeObjects.GenomicElementAndQueryMatch;
import genomeObjects.MotifGroup;
import genomeObjects.SequenceMotif;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import moduls.frm.ContextLeaf;
import moduls.frm.Panels.Jpan_btn_NEW;
import org.biojava3.core.sequence.Strand;
import org.sourceforge.jlibeps.epsgraphics.EpsGraphics2D;
public class RenderedGenomesPanel extends JPanel implements MouseListener{
private static final long serialVersionUID = 1L;
//fields
//biological + parent info
private GenomicSegment[] GS; //Genomic segment information
private mainFrame mf; //Genomes + other biological information
private RenderedGenomesPanel rgp; //this;
private HashMap<String, LinkedList<GenomicElementAndQueryMatch>> contexts; //Contexts
private HashMap<String, String> SourceSpecies; //Species Names
private HashMap<String, HashSet<String>> SourceContigs; //Contig Names
private String ECRONType; //Either "annotation" or "cluster"
//Range-limited related
private int RangeLimit = 50000; //Do not display a genomic region of this or more
private int SplitLimit = 50000; //segment contexts when they are further away from this value.
private LinkedList<String> ExceededRangeLimit; //nodes that are excluded
private boolean ContextsExcluded = false; //initially, none are excluded
//holding of split values
private LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>> SplitContexts;
private LinkedHashMap<String, String> SplitSpeciesNames;
private LinkedHashMap<String, HashSet<String>> SplitContigNames;
//display - related
private int GenomicDisplayRange; //nt range to display on each GS
private int CoordinateBarEvery; //nt block to display
private int BeforeBuffer; //nt range before actual context range
private int AfterBuffer; //nt range after actual context range
private double CenterScaleValue; //fraction of whole range where center of CS occurs
private double genome2displayRatio; //gene coordinate * <this> = xcoordinate to display
//export image stuff
private JPopupMenu ExportMenu; //export frame information
private Point PlaceClicked; //essential for export frame
//Display dimensions information
private Dimension dim; //Overall dimensions of display area
private int GSHeight = 50; //height of genomic segment
private int GSSpacer = 30; //vertical space between segments
private double GSStartFromLeft = 0.05;
private double GSSBufferOnRight = 0.05;
private int GenomeLineThickness = 2;
private int WholeWidthBuffer = 30;
private int GSWidth;
private int CoordinateBarWidth = 1;
private int ContigBoundaryWidth = 2;
private int ArrowLength = 20;
private int ArrowHeight = 10;
private int LabelAboveGS = 5;
//motifs
private boolean Motifs2Scale = false;
private int MotifWidthMinimum = (int) (GSHeight/6);
//boolean variables for check box repainting
private boolean ShowSurrounding = true;
private boolean ColorSurrounding = false;
private boolean StrandNormalize = true;
private boolean ShowCoordinates = true;
//mouse-related info
private boolean GeneInformationIsBeingDisplayed = false;
private JFrame GeneInfo;
private GeneColorLegendFrame gclf;
private GeneColorLegendPanel gclp;
private int FrameMoveDown = 38;
private int FrameMoveRight = 20;
private boolean ShowAnnotation = false;
private boolean ShowType = false;
private boolean ShowStart= false;
private boolean ShowStop = false;
private boolean ShowSize = false;
private boolean ShowClusterID = false;
private int CharacterMax = 20;
private boolean HomologyGroupSelected = false;
private DrawObject CurrentMiddleClickedDrawObject;
private DrawObject CurrentLeftClickedDrawObject;
private boolean ClickedOnLegend = false;
//legend panel info
private LinkedList<Color> CurrentlySelectedGeneColors;
private LinkedList<SharedHomology> GeneColorList;
private LinkedList<SharedHomology> DisplayedGeneColorList;
private LinkedList<SharedHomology> MotifColorList;
private LinkedList<SharedHomology> DisplayedMotifColorList;
private int OffSetPoint = 0;
//formatting information
private Font fontStandard = new Font("Dialog", Font.BOLD, 10);
final FontRenderContext renderContext = new FontRenderContext(null, true, true);
//Constructor
public RenderedGenomesPanel(mainFrame mfr){
super();
this.mf = mfr;
this.rgp = this;
this.addMouseListener(this);
//Retrieve settings
this.RangeLimit = mf.getFr().getCVS().RangeLimit;
this.SplitLimit = mf.getFr().getCVS().SplitLimit;
this.BeforeBuffer = mf.getFr().getCVS().DefaultRangeAround;
this.AfterBuffer = mf.getFr().getCVS().DefaultRangeAround;
//write in info from option panel
//this.BeforeBuffer = Integer.parseInt(this.mf.getOp().getStrbeforeRangeValue());
//this.AfterBuffer = Integer.parseInt(this.mf.getOp().getStrafterRangeValue());
//Splitting/editing
//Initialize holding places
SplitContexts = new LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>>();
SplitSpeciesNames = new LinkedHashMap<String, String>();
SplitContigNames = new LinkedHashMap<String, HashSet<String>>();
splitCrossContigGroupings(); //Adjust contexts
splitLargeGapGroupings(); //Adjust for large gaps within groupings
//computing segment info
this.dim = computeGenomicSegments();
this.setPreferredSize(dim); //key: preferredsize, not size
//computing information for display.
computeNucleotideRangesOnSegments();
addDrawGenes();
addMotifs();
addHomologyColors();
addCoordinateBars();
//create the Jpopupmenu
this.InitializeExportMenu();
//show missed
if (this.ContextsExcluded){
showExludedContexts();
}
}
// ----- export-related ------------------------------------------//
//create the pop-up menu object
private void InitializeExportMenu(){
//create action listener
ActionListener exportAction = new ActionListener(){
public void actionPerformed(final ActionEvent evt) {
//initialize context region
Integer ContextRegion = -1;
if (evt.getActionCommand().equals("Save contexts as JPG") ||
evt.getActionCommand().equals("Save contexts as PNG") ||
evt.getActionCommand().equals("Save contexts as EPS")) {
// SAVE WHOLE CONTEXT
try {
final BufferedImage buff;
//draw image and save picture
if (evt.getActionCommand().equals("Save contexts as JPG")){
buff = drawBufferedImage("jpg");
savePicture(buff, "jpg");
} else if (evt.getActionCommand().equals("Save contexts as PNG")){
buff = drawBufferedImage("png");
savePicture(buff, "png");
} else if (evt.getActionCommand().equals("Save contexts as EPS")){
String EPSString = drawEPS();
saveEPS(EPSString);
}
} catch (Exception e) {
}
//create a legend frame/
} else if (evt.getActionCommand().equals("Show Legend - Complete") ||
evt.getActionCommand().equals("Show Legend - Annotations") ||
evt.getActionCommand().equals("Show Legend - Clusters")){
//invoke the color list, unless there are no colors to report.
if (GeneColorList != null){
DetermineDisplayGeneColors();
if (evt.getActionCommand().equals("Show Legend - Complete")){
gclf = new GeneColorLegendFrame(rgp,DisplayedGeneColorList,"Complete");
gclp = gclf.getGclp();
} else if (evt.getActionCommand().equals("Show Legend - Annotations")){
gclf = new GeneColorLegendFrame(rgp,DisplayedGeneColorList,"Annotations");
gclp = gclf.getGclp();
} else if (evt.getActionCommand().equals("Show Legend - Clusters")){
gclf = new GeneColorLegendFrame(rgp,DisplayedGeneColorList,"Clusters");
gclp = gclf.getGclp();
}
}
}
}
};
//set export menu
this.ExportMenu = new JPopupMenu();
//create menu items
final JMenuItem me0 = new JMenuItem("Save contexts as JPG");
final JMenuItem me1 = new JMenuItem("Save contexts as PNG");
final JMenuItem me2 = new JMenuItem("Save contexts as EPS");
final JMenuItem me3 = new JMenuItem("Show Legend - Complete");
final JMenuItem me4 = new JMenuItem("Show Legend - Annotations");
final JMenuItem me5 = new JMenuItem("Show Legend - Clusters");
//add action listeners
me0.addActionListener(exportAction);
me1.addActionListener(exportAction);
me2.addActionListener(exportAction);
me3.addActionListener(exportAction);
me4.addActionListener(exportAction);
me5.addActionListener(exportAction);
//build menu
ExportMenu.add(me0);
ExportMenu.add(me1);
ExportMenu.add(me2);
ExportMenu.addSeparator();
ExportMenu.add(me3);
if (this.ECRONType.contentEquals("annotation")){
ExportMenu.add(me4);
} else {
ExportMenu.add(me5);
}
}
//determine displayed gene colors
private void DetermineDisplayGeneColors(){
//initialize output
DisplayedGeneColorList = new LinkedList<SharedHomology>();
// all genes in the range are displayed
if (ShowSurrounding == true && ColorSurrounding == true){
DisplayedGeneColorList = GeneColorList;
} else { //only show query matches
//initialize a hash set
HashSet<SharedHomology> SHash = new HashSet<SharedHomology>();
//add all appropriate colored genes to the hashset
for (int i = 0; i < GS.length; i++){
for (DrawGene dg : GS[i].getDg()){
if (dg.getMembership() == 0){
for (SharedHomology SH : GeneColorList){
if (ECRONType.equals("annotation")){
if (SH.getAnnotation().contentEquals(dg.getBioInfo().getAnnotation().toUpperCase())){
SHash.add(SH);
break;
}
} else {
if (SH.getClusterID()==dg.getBioInfo().getClusterID()){
SHash.add(SH);
break;
}
}
}
}
}
}
//add all appropriate motifs to the hashset
for (int i = 0; i < GS.length; i++){
for (DrawMotif dm : GS[i].getDm()){
if (dm.getMembership() == 0){
for (SharedHomology SH : MotifColorList){
if (SH.getAnnotation().contentEquals(dm.getBioInfo().getMotifName().toUpperCase())){
SHash.add(SH);
break;
}
}
}
}
}
//create an iterator for the HashSet, remove duplicate entries
Iterator<SharedHomology> it = SHash.iterator();
while (it.hasNext()){
SharedHomology SH = it.next();
DisplayedGeneColorList.add(SH);
}
}
}
//method to save picture
private void savePicture(BufferedImage buff, String extension) {
String sPath;
String sNameNoExt = Jpan_btn_NEW.getFileNameNoExt();
final FileDialog fd = new FileDialog(mf, "Export " +
extension.toUpperCase() + " Image", FileDialog.SAVE);
fd.setFile(sNameNoExt + "." + extension);
fd.setVisible(true);
if (fd.getFile() != null){
sPath = fd.getDirectory() + fd.getFile();
final File OutputFile = new File(sPath);
try {
ImageIO.write(buff, extension, OutputFile);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Image Writing Error",
"The picture could not be created.",JOptionPane.ERROR_MESSAGE);
}
}
}
//generate JPG or PNG image
private BufferedImage drawBufferedImage(String extension){
if (extension.contentEquals("jpg") ||
extension.contentEquals("png")) {
Graphics2D g2d;
final double width_Mon = this.getSize().getWidth();
final double height_Mon = this.getSize().getHeight();
final BufferedImage buff = new BufferedImage((int) width_Mon,
(int) height_Mon, BufferedImage.TYPE_INT_RGB);
g2d = buff.createGraphics();
this.paintComponent(g2d);
g2d.dispose();
return buff;
} else {
return null;
}
}
//produce an EPS
private String drawEPS(){
EpsGraphics2D g2d = new EpsGraphics2D();
this.paintComponent(g2d);
return g2d.toString();
}
//save an EPS
private void saveEPS(String EPS){
String sPath;
String sNameNoExt = Jpan_btn_NEW.getFileNameNoExt();
final FileDialog fd = new FileDialog(mf, "Export EPS Image", FileDialog.SAVE);
fd.setFile(sNameNoExt + ".eps");
fd.setVisible(true);
if (fd.getFile() != null){
sPath = fd.getDirectory() + fd.getFile();
final File OutputFile = new File(sPath);
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(OutputFile));
bw.write(EPS); bw.flush(); bw.close();
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Image Saving Error",
"The picture could not be saved.",JOptionPane.ERROR_MESSAGE);
}
}
}
// ----- pre-drawing computations -----------------------------------//
//split cross-contig genomic groupings
public void splitCrossContigGroupings(){
//Retrieve original data
CSDisplayData CSD = this.mf.getCSD();
//Initialize updated list
LinkedList<ContextLeaf> UpdatedCL = new LinkedList<ContextLeaf>();
//split contexts based on common contig.
for (ContextLeaf CL : CSD.getGraphicalContexts()){
if (CL.isSelected()){
//Retrieve original set
String LeafName = CL.getName();
LinkedList<GenomicElementAndQueryMatch> LL = CSD.getEC().getContexts().get(LeafName);
//split the set, based on contig
LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>>
SequenceElementMapping = new LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>>();
//iterate through all contig names
Iterator<String> it = CSD.getEC().getSourceContigNames().get(LeafName).iterator();
while (it.hasNext()){
//current contig
String Contig = it.next();
//create output
LinkedList<GenomicElementAndQueryMatch> SL = new LinkedList<GenomicElementAndQueryMatch>();
//pull out subset
for (GenomicElementAndQueryMatch GandE : LL){
if (GandE.getE().getContig().equals(Contig)){
SL.add(GandE);
}
}
//map
SequenceElementMapping.put(Contig, SL);
}
//remake set, if appropriate
if (SequenceElementMapping.size() > 1){
//retrieve information
HashSet<String> ContigName = CSD.getEC().getSourceContigNames().get(LeafName);
String SourceName= CSD.getEC().getSourceSpeciesNames().get(LeafName);
//store information, prior to removal, if it is basic
if (CL.isSearchReturnedContext()){
SplitContexts.put(LeafName, LL);
SplitContigNames.put(LeafName, ContigName);
SplitSpeciesNames.put(LeafName, SourceName);
}
//remove old sets
CSD.getEC().getContexts().remove(LeafName);
CSD.getEC().getSourceContigNames().remove(LeafName);
CSD.getEC().getSourceSpeciesNames().remove(LeafName);
//initialize counter
int ContigCounter = 0;
for (String CN : SequenceElementMapping.keySet()){
//increment counter
ContigCounter++;
//retrieve output
LinkedList<GenomicElementAndQueryMatch> SL = SequenceElementMapping.get(CN);
//Updated leaf name
String UpdatedLeafName = LeafName + ", Sequence " + String.valueOf(ContigCounter);
//all other information is the same, except for name
ContextLeaf NewLeaf = new ContextLeaf();
NewLeaf.setSelected(true);
NewLeaf.setName(UpdatedLeafName);
NewLeaf.setSearchReturnedContext(false);
//update contexts, species, and sequence names
CSD.getEC().getContexts().put(UpdatedLeafName, SL);
CSD.getEC().getSourceSpeciesNames().put(UpdatedLeafName, SourceName);
//map to a new set of contigs
HashSet<String> UpdatedContigNames = new HashSet<String>();
UpdatedContigNames.add(CN);
CSD.getEC().getSourceContigNames().put(UpdatedLeafName, UpdatedContigNames);
//add to list
UpdatedCL.add(NewLeaf);
}
} else {
UpdatedCL.add(CL);
}
} else {
UpdatedCL.add(CL);
}
}
//reformat into an array.
ContextLeaf[] UpdatedContexts = new ContextLeaf[UpdatedCL.size()];
for (int i = 0; i < UpdatedContexts.length; i++){
UpdatedContexts[i] = UpdatedCL.get(i);
}
//update data structure
CSD.setGraphicalContexts(UpdatedContexts);
//return data
this.mf.setCSD(CSD);
}
//split gene groupings with elements that span a large gap
public void splitLargeGapGroupings(){
//Retrieve original data
CSDisplayData CSD = this.mf.getCSD();
//Initialize updated list
LinkedList<ContextLeaf> UpdatedCL = new LinkedList<ContextLeaf>();
for (ContextLeaf CL : CSD.getGraphicalContexts()){
if (CL.isSelected()){
//Retrieve original set
String LeafName = CL.getName();
LinkedList<GenomicElementAndQueryMatch> LL = CSD.getEC().getContexts().get(LeafName);
//split the set, based on size
LinkedHashMap<int[], LinkedList<GenomicElementAndQueryMatch>>
SequenceElementMapping = new LinkedHashMap<int[], LinkedList<GenomicElementAndQueryMatch>>();
for (GenomicElementAndQueryMatch GandE : LL){
//mapped or not
boolean ElementMapped = false;
//check all existing groups
for (int[] Key : SequenceElementMapping.keySet()){
//compare to key
//(1) gene falls within existing limits
//(2) adding this gene and updating limits does not change much.
if (((GandE.getE().getStart() > Key[0] && GandE.getE().getStop() < Key[1])) ||
Math.max(Key[1], GandE.getE().getStop())-Math.min(Key[0],GandE.getE().getStart()) <= SplitLimit){
//update the key, for reloading in the hash map.
int[] UpdatedKey = {Math.min(Key[0], GandE.getE().getStart()), Math.max(Key[1], GandE.getE().getStop())};
//retrieve entries + update
LinkedList<GenomicElementAndQueryMatch> Entries = SequenceElementMapping.get(Key);
Entries.add(GandE);
//update hash map
SequenceElementMapping.remove(Key);
SequenceElementMapping.put(UpdatedKey, Entries);
//break out of the loop -> this entry has been mapped.
ElementMapped = true;
break;
}
}
//map the element, if needed.
if (!ElementMapped){
//if need be, create a new entry.
//create key
int[] NewKey = {GandE.getE().getStart(), GandE.getE().getStop()};
//create value
LinkedList<GenomicElementAndQueryMatch> NewGroup =
new LinkedList<GenomicElementAndQueryMatch>();
NewGroup.add(GandE);
//insert into hashmap
SequenceElementMapping.put(NewKey,NewGroup);
}
}
//remake set, if appropriate
if (SequenceElementMapping.size() > 1){
//retrieve information
HashSet<String> ContigName = CSD.getEC().getSourceContigNames().get(LeafName);
String SourceName= CSD.getEC().getSourceSpeciesNames().get(LeafName);
//store information, prior to removal
SplitContexts.put(LeafName, LL);
SplitContigNames.put(LeafName, ContigName);
SplitSpeciesNames.put(LeafName, SourceName);
//remove old sets
CSD.getEC().getContexts().remove(LeafName);
CSD.getEC().getSourceContigNames().remove(LeafName);
CSD.getEC().getSourceSpeciesNames().remove(LeafName);
//initialize counter
int ContigCounter = 0;
for (LinkedList<GenomicElementAndQueryMatch> SL : SequenceElementMapping.values()){
//increment counter
ContigCounter++;
//Updated leaf name
String UpdatedLeafName = LeafName + ", Segment " + String.valueOf(ContigCounter);
//all other information is the same, except for name
ContextLeaf NewLeaf = new ContextLeaf();
NewLeaf.setSelected(true);
NewLeaf.setName(UpdatedLeafName);
NewLeaf.setSearchReturnedContext(false);
//update contexts, species, and sequence names
CSD.getEC().getContexts().put(UpdatedLeafName, SL);
CSD.getEC().getSourceSpeciesNames().put(UpdatedLeafName, SourceName);
CSD.getEC().getSourceContigNames().put(UpdatedLeafName, ContigName);
//add to list
UpdatedCL.add(NewLeaf);
}
} else {
UpdatedCL.add(CL);
}
} else {
UpdatedCL.add(CL);
}
}
//reformat into an array.
ContextLeaf[] UpdatedContexts = new ContextLeaf[UpdatedCL.size()];
for (int i = 0; i < UpdatedContexts.length; i++){
UpdatedContexts[i] = UpdatedCL.get(i);
}
//update data structure
CSD.setGraphicalContexts(UpdatedContexts);
//return data
this.mf.setCSD(CSD);
}
//create genomic segments
private Dimension computeGenomicSegments() {
//acceptable segments + unacceptable segments
LinkedList<GenomicSegment> AcceptableSegments =
new LinkedList<GenomicSegment>();
ExceededRangeLimit = new LinkedList<String>();
//determine number of segments
int SegmentstoDraw = 0;
for (ContextLeaf CL : this.mf.getCSD().getGraphicalContexts()){
if (CL.isSelected()){
SegmentstoDraw++;
}
}
//initialize output variable, and dimension info
Dimension ThisDimension = new Dimension();
int DimTotalHeight = 0;
Dimension d = this.mf.getDim();
int DimTotalWidth = (int) d.getWidth() - WholeWidthBuffer;
GSWidth = (int)(DimTotalWidth*(1-GSStartFromLeft-GSSBufferOnRight));
//initialize array
GS = new GenomicSegment[SegmentstoDraw];
//retrieve biological information
contexts = mf.getCSD().getEC().getContexts();
SourceSpecies = mf.getCSD().getEC().getSourceSpeciesNames();
SourceContigs = mf.getCSD().getEC().getSourceContigNames();
//What to do about this? should the display type possibly be an option?
ECRONType = mf.getCSD().getEC().getSearchType();
// if (mf.getOS().isGeneClustersLoaded()){
// ECRONType = "cluster";
// } else {
// ECRONType = "annotation";
// }
int LongestRange = 0;
//add information
int CoordinateNumber = -1;
for (ContextLeaf CL : this.mf.getCSD().getGraphicalContexts()){
if (CL.isSelected()){
//initialize a new genomic segment
GenomicSegment GSelement = new GenomicSegment();
//note query match info
int QueryStrandPlus = 0; int QueryStrandMinus = 0;
//add node name
GSelement.setLabel(CL.getName());
//determine the longest range
LinkedList<GenomicElementAndQueryMatch> LL = contexts.get(GSelement.getLabel());
//reset start and stop variables for every genomic element processed
int Start = 99999999; int Stop = -1;
//determine range information + query match information.
for (GenomicElementAndQueryMatch e : LL){
//determine range information
if (e.getE().getStart() < Start){
Start = e.getE().getStart();
}
if (e.getE().getStop() > Stop){
Stop = e.getE().getStop();
}
//query-match orientation information
if (e.isQueryMatch()){
if (e.getE().getStrand().equals(Strand.POSITIVE)){
QueryStrandPlus++;
} else {
QueryStrandMinus++;
}
}
}
//query match-related
//setting to flip all genes in the event of strand-normalized display
if (QueryStrandMinus > QueryStrandPlus){
GSelement.setStrRevFlipGenes(true);
}
//only add this element to the list if the range is acceptable.
if ((Stop - Start) < RangeLimit) {
//increment coordinate number
CoordinateNumber++;
//set values for this CS
GSelement.setStartCS(Start);
GSelement.setStartAfterBuffer(Stop);
GSelement.setCenterofCS((int) Math.round((double)(0.5*(Start+Stop))));
//bounding rectangle
Rectangle2D rect =
new Rectangle((int) (DimTotalWidth*GSStartFromLeft),
(int)(((GSHeight+GSSpacer)*CoordinateNumber)+GSSpacer),
GSWidth,GSHeight);
//add bounding rectangle to the set of GS elements
GSelement.setBoundingRect(rect);
//compare to current longest range
if ((Stop-Start) > LongestRange){
LongestRange = Stop-Start;
}
//segment is acceptable
AcceptableSegments.add(GSelement);
} else {
//ExceededRangeLimit.add(this.mf.getCSD().getNodeNames()[i]);
ExceededRangeLimit.add(CL.getName());
ContextsExcluded = true;
}
}
}
CoordinateNumber = -1;
//from the list of acceptable nodes, determine rendering regions.
GS = new GenomicSegment[AcceptableSegments.size()];
for (int i = 0; i < AcceptableSegments.size(); i++){
GS[i] = AcceptableSegments.get(i);
CoordinateNumber++;
}
//determine the total height
DimTotalHeight = (GSHeight + GSSpacer)*(CoordinateNumber+1)+ 2*GSSpacer;
//genomic display ranges
GenomicDisplayRange = LongestRange + BeforeBuffer + AfterBuffer;
CenterScaleValue = (BeforeBuffer + 0.5*((double)LongestRange))/GenomicDisplayRange;
genome2displayRatio = ((double)GSWidth/(double)GenomicDisplayRange);
//Determine where to put center of CS, relative to whole size
//optional print statements
// System.out.println("Display Range: " + GenomicDisplayRange + " nt.");
// System.out.println(CenterScaleValue);
// System.out.println(genome2displayRatio);
ThisDimension.setSize(DimTotalWidth,DimTotalHeight); //dimension of panel
return ThisDimension;
}
//add range information
private void computeNucleotideRangesOnSegments() {
int NtBeforeCenter; int NtAfterCenter;
int GSStart; int GSEnd;
for (int i = 0; i <GS.length; i++){
//determine values
NtBeforeCenter = (int) (CenterScaleValue*GenomicDisplayRange);
GSStart = GS[i].getCenterofCS() - NtBeforeCenter;
NtAfterCenter = (int) ((1 - CenterScaleValue)*GenomicDisplayRange);
GSEnd = GS[i].getCenterofCS() + NtAfterCenter;
//set values
GS[i].setStartBeforeBuffer(GSStart);
GS[i].setEndRange(GSEnd);
}
}
//add genes to bounding rectangles (no other features)
private void addDrawGenes(){
for (int i = 0; i <GS.length; i++){
//Initialize drawgenes output structures
LinkedList<DrawGene> dgs = new LinkedList<DrawGene>();
//retrieve species + contig name
String SpeciesName = SourceSpecies.get(GS[i].getLabel());
String ContigName = SourceContigs.get(GS[i].getLabel()).iterator().next();
//debugging: print statements
//System.out.println(i + ": " + SpeciesName + "-" + ContigName);
//TODO: modifications, of course!
//retrieve genome - load if necessary
mf.getOS().AdjustAvailableSpecies(SpeciesName);
AnnotatedGenome AG = mf.getOS().getSpecies().get(SpeciesName);
//information
int GeneX; int GeneY; int GeneWidth; int GeneHeight;
//iterate through elements, and add coordinates
//this approach assumes an unsorted list
//iterate through all genes
for (GenomicElement e : AG.getElements()){
//check and see if this element should be retained at all
//check include types
boolean DisplayElement = false;
for (String s : AG.getIncludeTypes()){
if (e.getType().contentEquals(s)){
DisplayElement = true;
break;
}
}
//if this fails, check for display only types
if (!DisplayElement){
for (String s : AG.getDisplayOnlyTypes()){
if (e.getType().contentEquals(s)){
DisplayElement = true;
break;
}
}
}
if ((((e.getStart() < GS[i].getStartBeforeBuffer() && e.getStop() < GS[i].getStartBeforeBuffer()) ||
(e.getStart() > GS[i].getEndRange() && e.getStop() > GS[i].getEndRange())) == false) &&
(DisplayElement) && e.getContig().equals(ContigName)){
//upon discovering a single gene, initialize a new "drawgene"
DrawGene dg = new DrawGene();
//add information relevant for coloring
dg.setBioInfo(e);
dg.setSourceSpecies(AG.getSpecies());
//determine rendering coordinates of the rectangle
boolean TruncatedStart = false;
//x-coordinates
//truncate beginning
if (e.getStart() < GS[i].getStartBeforeBuffer()){
GeneX = (int) GS[i].getBoundingRect().getMinX();
TruncatedStart = true;
} else {
GeneX = (int) ((genome2displayRatio * (e.getStart()-GS[i].getStartBeforeBuffer()))
+ GS[i].getBoundingRect().getMinX());
}
//y-coordinate (here, consider strandedness)
GeneY = (int) GS[i].getBoundingRect().getCenterY();
//width (consider truncating the end)
if (e.getStop() > GS[i].getEndRange()){
GeneWidth = (int) (GS[i].getBoundingRect().getMaxX()) - GeneX;
} else {
if (TruncatedStart == false){
GeneWidth = (int)(genome2displayRatio * (e.getStop() - e.getStart()));
} else {
GeneWidth = (int)(genome2displayRatio * (e.getStop() - GS[i].getStartBeforeBuffer()));
}
}
//Height (always the same)
GeneHeight = (int) (GSHeight/3);
//Y-coordinate starting point (strandedness matters)
if (e.getStrand().equals(Strand.POSITIVE)){
GeneY = (int) GS[i].getBoundingRect().getCenterY() - GeneHeight;
} else {
//GeneY = (int) GS[i].getBoundingRect().getCenterY(); //original
GeneY = (int) GS[i].getBoundingRect().getCenterY()+1; //add 1 for display problems
}
//create rectangle with appropriate values
Rectangle gene = new Rectangle(GeneX, GeneY, GeneWidth, GeneHeight);
dg.setCoordinates(gene);
//strand-reversed case
if (GS[i].isStrRevFlipGenes()){
//height+width do not change
int GeneHeightFlip = GeneHeight;
int GeneWidthFlip = GeneWidth;
int GeneYFlip;
//determine Y-coordinate
if (GeneY == (int) GS[i].getBoundingRect().getCenterY()+1){ //edit with +1 for display problem
GeneYFlip = (int) GS[i].getBoundingRect().getCenterY() - GeneHeight;
} else {
//GeneYFlip = (int) GS[i].getBoundingRect().getCenterY();// original
GeneYFlip = (int) GS[i].getBoundingRect().getCenterY()+1;// add 1 for display problems
}
//determine X-coordinate
double Dist2Center = Math.abs(GeneX - GS[i].getBoundingRect().getCenterX());
int GeneXFlip;
if (GeneX > GS[i].getBoundingRect().getCenterX()){
GeneXFlip = (int) (GeneX - 2*Dist2Center - GeneWidth);
} else {
GeneXFlip = (int) (GeneX + 2*Dist2Center - GeneWidth);
}
//draw rectangle, and store
Rectangle geneFlip = new Rectangle(GeneXFlip, GeneYFlip, GeneWidthFlip, GeneHeightFlip);
dg.setStrRevCoordinates(geneFlip);
dg.setStrRevChange(true);
} else {
dg.setStrRevCoordinates(gene);
dg.setStrRevChange(false);
}
//determine membership
//Update: compare to ECRON as opposed to range boundaries
LinkedList<GenomicElementAndQueryMatch> LL = contexts.get(GS[i].getLabel());
boolean MemberOfContextSet = false;
for (int j = 0; j <LL.size(); j++){
if (e.getStart() == LL.get(j).getE().getStart() &&
e.getStop() == LL.get(j).getE().getStop()){
MemberOfContextSet = true;
}
}
if (MemberOfContextSet == true){
dg.setMembership(0);
} else {
dg.setMembership(-1);
}
//set color to default
dg.setColor(Color.LIGHT_GRAY);
//add this draw gene to the set
dgs.add(dg);
}
}
//update draw genes
GS[i].setDg(dgs);
}
}
//add motifs to contexts
private void addMotifs(){
for (int i = 0; i <GS.length; i++){
//Initialize drawgenes output structures
LinkedList<DrawMotif> dms = new LinkedList<DrawMotif>();
//retrieve species + contig name
String SpeciesName = SourceSpecies.get(GS[i].getLabel());
String ContigName = SourceContigs.get(GS[i].getLabel()).iterator().next();
//retrieve genome
AnnotatedGenome AG = mf.getOS().getSpecies().get(SpeciesName);
//information
int MotifX; int MotifY; int MotifWidth; int MotifHeight;
//iterate through elements, and add coordinates
//this approach assumes an unsorted list
//iterate through all significant sequences
for (MotifGroup MG : AG.getMotifs()){
for (SequenceMotif SM : MG.getMotifInstances()){
if ((((SM.getStart() < GS[i].getStartBeforeBuffer() && SM.getStop() < GS[i].getStartBeforeBuffer()) ||
(SM.getStart() > GS[i].getEndRange() && SM.getStop() > GS[i].getEndRange()))==false) &&
SM.getContig().equals(ContigName)){
//Debugging: display motif
//System.out.println("DrawMotif: " + AG.getSpecies() + "," + SM.getContig() + " " + SM.getStart() + ":" + SM.getStop() + " " + SM.getStrand().toString());
//Initialize draw motif
DrawMotif dm = new DrawMotif();
//set information relevant for coloring
dm.setBioInfo(SM);
//determine rendering coordinates of the ellipse
boolean TruncatedStart = false;
//x-coordinates
//truncate beginning
if (SM.getStart() < GS[i].getStartBeforeBuffer()){
MotifX = (int) GS[i].getBoundingRect().getMinX();
TruncatedStart = true;
} else {
MotifX = (int) ((genome2displayRatio * (SM.getStart()-GS[i].getStartBeforeBuffer()))
+ GS[i].getBoundingRect().getMinX());
}
//y-coordinate (here, consider strandedness)
MotifY = (int) GS[i].getBoundingRect().getCenterY();
//width (consider truncating the end)
if (SM.getStop() > GS[i].getEndRange()){
MotifWidth = (int) (GS[i].getBoundingRect().getMaxX()) - MotifX;
} else {
if (TruncatedStart == false){
MotifWidth = (int)(genome2displayRatio * (SM.getStop() - SM.getStart()));
} else {
MotifWidth = (int)(genome2displayRatio * (SM.getStop() - GS[i].getStartBeforeBuffer()));
}
}
//Height (always the same)
MotifHeight = (int) (GSHeight/3);
//Y-coordinate starting point (strandedness matters)
if (SM.getStrand().equals(Strand.POSITIVE)){
MotifY = (int) GS[i].getBoundingRect().getCenterY() - MotifHeight;
} else {
//GeneY = (int) GS[i].getBoundingRect().getCenterY(); //original
MotifY = (int) GS[i].getBoundingRect().getCenterY()+1; //add 1 for display problems
}
//note original motif width
int OriginalMotifWidth = MotifWidth;
//update motif width, if appropriate
if (!Motifs2Scale)
if (MotifWidth < MotifWidthMinimum){
MotifWidth = MotifWidthMinimum;
}
//create ellipse with appropriate values
Ellipse2D motif = new Ellipse2D.Double((double)MotifX, (double)MotifY, (double)MotifWidth, (double)MotifHeight);
dm.setCoordinates(motif);
//strand-reversed case
if (GS[i].isStrRevFlipGenes()){
//height+width do not change
int MotifHeightFlip = MotifHeight;
int MotifWidthFlip = OriginalMotifWidth;
int MotifYFlip;
//determine Y-coordinate
if (MotifY == (int) GS[i].getBoundingRect().getCenterY()+1){ //edit with +1 for display problem
MotifYFlip = (int) GS[i].getBoundingRect().getCenterY() - MotifHeight;
} else {
MotifYFlip = (int) GS[i].getBoundingRect().getCenterY()+1;// add 1 for display problems
}
//determine X-coordinate
double Dist2Center = Math.abs(MotifX - GS[i].getBoundingRect().getCenterX());
int MotifXFlip;
if (MotifX > GS[i].getBoundingRect().getCenterX()){
MotifXFlip = (int) (MotifX - 2*Dist2Center - OriginalMotifWidth);
} else {
MotifXFlip = (int) (MotifX + 2*Dist2Center - OriginalMotifWidth);
}
//update flipped motif width, if appropriate
if (!Motifs2Scale)
if (MotifWidthFlip < MotifWidthMinimum){
MotifWidthFlip = MotifWidthMinimum;
}
//create ellipse with appropriate values
Ellipse2D motifFlip = new Ellipse2D.Double((double)MotifXFlip, (double)MotifYFlip, (double)MotifWidthFlip, (double)MotifHeightFlip);
dm.setStrRevCoordinates(motifFlip);
dm.setStrRevChange(true);
} else {
dm.setStrRevCoordinates(motif);
dm.setStrRevChange(false);
}
//determine membership
LinkedList<GenomicElementAndQueryMatch> LL = contexts.get(GS[i].getLabel());
boolean MemberOfContextSet = false;
for (int j = 0; j <LL.size(); j++){
if (LL.get(j).getE().getAssociatedMotifs().contains(SM)){
MemberOfContextSet = true;
}
}
if (MemberOfContextSet == true){
dm.setMembership(0);
} else {
dm.setMembership(-1);
}
//set color to default
dm.setColor(Color.LIGHT_GRAY);
//add this draw gene to the set
dms.add(dm);
}
}
}
//update draw genes
GS[i].setDm(dms);
}
}
//add appropriate colors according to homology
private void addHomologyColors() {
//reset offset point
this.OffSetPoint = 0;
if (ECRONType.equals("annotation")){
//define a new counting array
Count<String, Integer> AnnColors = new Count<String, Integer>();
//collect all colors
for (int i = 0; i < GS.length; i++){
for (int j = 0; j <GS[i].getDg().size(); j++){
AnnColors.add(GS[i].getDg().get(j).getBioInfo().getAnnotation().toUpperCase());
}
}
//sort annotations into a linked list
LinkedList<SharedHomology> AnnColorsSorted = SortAndAddColors2Ann(AnnColors);
//set
this.GeneColorList = AnnColorsSorted;
//add these colors back to the elements
for (int i = 0; i < GS.length; i++){
for (int j = 0; j < GS[i].getDg().size(); j++){
for (int k = 0; k < AnnColorsSorted.size(); k++){
if (AnnColorsSorted.get(k).getAnnotation().equals(GS[i].getDg().get(j).getBioInfo().getAnnotation().toUpperCase())){
//set color appropriately
GS[i].getDg().get(j).setColor(AnnColorsSorted.get(k).getColor());
//add all elements to the shared homology colors for later parsing
AnnColorsSorted.get(k).getMembers().add(GS[i].getDg().get(j).getBioInfo());
}
}
}
}
} else if (ECRONType.equals("cluster")){
//Debugging
//System.out.println("Type is cluster!!");
//define a new counting array
Count<Integer, Integer> AnnColors = new Count<Integer, Integer>();
//collect all colors
for (int i = 0; i < GS.length; i++){
for (int j = 0; j <GS[i].getDg().size(); j++){
AnnColors.add(GS[i].getDg().get(j).getBioInfo().getClusterID());
}
}
//sort Cluster IDs into a linked list
LinkedList<SharedHomology> AnnColorsSorted = SortAndAddColors2Cluster(AnnColors);
this.GeneColorList = AnnColorsSorted;
//debugging
//System.out.println("assigning colors.");
//add these colors back to the elements
for (int i = 0; i < GS.length; i++){
for (int j = 0; j < GS[i].getDg().size(); j++){
for (int k = 0; k < AnnColorsSorted.size(); k++){
if (AnnColorsSorted.get(k).getClusterID() == GS[i].getDg().get(j).getBioInfo().getClusterID()){
//set color appropriately
GS[i].getDg().get(j).setColor(AnnColorsSorted.get(k).getColor());
// //for debugging - problem here?
// if (GS[i].getDg().get(j).getBioInfo().getClusterID() == 144){
// DrawGene DG = GS[i].getDg().get(j);
// String str = "Org= "+ DG.getSourceSpecies() +
// " Contig= " + DG.getBioInfo().getContig() +
// " Color= " + DG.getColor().toString();
// System.out.println(str);
// }
//add all elements to the shared homology colors for later parsing
AnnColorsSorted.get(k).getMembers().add(GS[i].getDg().get(j).getBioInfo());
}
}
}
}
}
//adjust offset point
this.OffSetPoint = this.GeneColorList.size();
//Add colors to motifs
//define a new counting array
Count<String, Integer> MotifColors = new Count<String, Integer>();
//collect all colors
for (int i = 0; i < GS.length; i++){
for (int j = 0; j <GS[i].getDm().size(); j++){
MotifColors.add(GS[i].getDm().get(j).getBioInfo().getMotifName().toUpperCase());
}
}
//sort annotations into a linked list
LinkedList<SharedHomology> MotifColorsSorted = SortAndAddColors2Ann(MotifColors);
//set
this.MotifColorList = MotifColorsSorted;
//add these colors back to the elements
for (int i = 0; i < GS.length; i++){
if (GS[i].getDm() != null){
for (int j = 0; j < GS[i].getDm().size(); j++){
for (int k = 0; k < MotifColorsSorted.size(); k++){
if (MotifColorsSorted.get(k).getAnnotation().equals(GS[i].getDm().get(j).getBioInfo().getMotifName().toUpperCase())){
//set color appropriately
GS[i].getDm().get(j).setColor(MotifColorsSorted.get(k).getColor());
//add all elements to the shared homology colors for later parsing
MotifColorsSorted.get(k).getMotifMembers().add(GS[i].getDm().get(j).getBioInfo());
}
}
}
}
}
//reset offset point
this.OffSetPoint = 0;
// //Debugging - everything showing up as blue (which is correct)
// for (int i = 0; i < GS.length; i++){
// for (DrawGene DG : GS[i].getDg()){
// if (DG.getBioInfo().getClusterID() == 144){
// String str = "Org= "+ DG.getSourceSpecies() +
// " Contig= " + DG.getBioInfo().getContig() +
// " Color= " + DG.getColor().toString();
// System.out.println(str);
// }
// }
// }
}
//add coordinate bars
private void addCoordinateBars(){
//coordinates to show depends on the size of the display range
//subject to change
if (GenomicDisplayRange < 1000){
CoordinateBarEvery = 100;
} else if (GenomicDisplayRange < 2000){
CoordinateBarEvery = 200;
} else if (GenomicDisplayRange < 3000){
CoordinateBarEvery = 500;
} else if (GenomicDisplayRange < 5000){
CoordinateBarEvery = 1000;
} else if (GenomicDisplayRange < 10000){
CoordinateBarEvery = 2000;
} else if (GenomicDisplayRange < 15000){
CoordinateBarEvery = 3000;
} else if (GenomicDisplayRange < 20000){
CoordinateBarEvery = 5000;
} else if (GenomicDisplayRange < 50000){
CoordinateBarEvery = 10000;
} else {
CoordinateBarEvery = 20000;
}
//add bars for non-strand corrected case
for (int i = 0; i < GS.length; i++){
int StartValue;
//round to nearest hundredth, thousandth, or ten-thousandth.
// if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 1000){
// StartValue = 10 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/10.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 10000){
// StartValue = 100 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/100.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 100000){
// StartValue = 1000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/1000.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 1000000) {
// StartValue = 10000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/10000.0);
// } else {
// StartValue = 100000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/100000.0);
// }
//round to nearest 1000, if possible
//
// System.out.println("Start: " + GS[i].getStartBeforeBuffer());
// System.out.println("Ceiling: " + (int) (1000 * Math.ceil(GS[i].getStartBeforeBuffer()/1000)+1000));
// if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 1000){
// StartValue = 100 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/100.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 10000){
// StartValue = 1000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/1000.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 100000){
// StartValue = 1000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/1000.0);
// } else if (GS[i].getEndRange()-GS[i].getStartAfterBuffer() < 1000000) {
// StartValue = 1000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/1000.0);
// } else {
// StartValue = 1000 * (int) Math.ceil(GS[i].getStartBeforeBuffer()/1000.0);
// }
//round to nearest 1000
if (GS[i].getEndRange() > 1000){
StartValue = (int) (1000 * Math.ceil(GS[i].getStartBeforeBuffer()/1000)+1000);
} else {
StartValue = 0;
}
// //optional print statement
// System.out.println("Span: " + GS[i].getStartBeforeBuffer()
// + ":" + GS[i].getEndRange() + " , First: " + StartValue);
//add coordinate bars
LinkedList<Integer> barpositions = new LinkedList<Integer>();
LinkedList<Integer> barvalues = new LinkedList<Integer>();
//write info to output
while (StartValue < GS[i].getEndRange()){
barvalues.add(StartValue);
barpositions.add((int)(GS[i].getBoundingRect().getMinX()+(genome2displayRatio*(StartValue-GS[i].getStartBeforeBuffer()))));
//optional print statements
// System.out.println("min x: " + GS[i].getBoundingRect().getMinX());
// System.out.println("value: " + (int)(GS[i].getBoundingRect().getMinX()+(genome2displayRatio*(StartValue-GS[i].getStartBeforeBuffer()))));
// System.out.println(GS[i].getEndRange()-StartValue);
// System.out.println(GS[i].getBoundingRect().getMinX());
// System.out.println((GS[i].getEndRange()-StartValue));
//+ GS[i].getEndRange()-StartValue)
//System.out.println("Value: " + (int)(GS[i].getBoundingRect().getMinX()+(genome2displayRatio*(GS[i].getEndRange()-StartValue))));
StartValue = StartValue + CoordinateBarEvery;
}
//store appropriate values
GS[i].setBarPositions(barpositions);
GS[i].setBarValues(barvalues);
//initialize list
LinkedList<Integer> ContigBoundaries = new LinkedList<Integer>();
//contig boundary 1: zero boundary
if (GS[i].getStartBeforeBuffer() <= 0){
ContigBoundaries.add((int)(GS[i].getBoundingRect().getMinX()+
(genome2displayRatio*(-1.0*GS[i].getStartBeforeBuffer()))));
}
//contig boundary 2: end of contig
//retrieve contig end
int ContigLimit = -1;
if (mf.getFr().getOS().getSpecies().get(GS[i].getDg().get(0).getSourceSpecies()).getContigEnds().get(GS[i].getDg().get(0).getBioInfo().getContig()) != null){
ContigLimit = mf.getFr().getOS().getSpecies().get(GS[i].getDg().get(0).getSourceSpecies()).getContigEnds().get(GS[i].getDg().get(0).getBioInfo().getContig());
}
//draw a line, if appropriate
if (ContigLimit != -1){
//add lines, if appropriate
if (ContigLimit < GS[i].getEndRange()){
ContigBoundaries.add((int)(GS[i].getBoundingRect().getMinX()+
(genome2displayRatio*(ContigLimit-GS[i].getStartBeforeBuffer()))));
}
}
//add
if (ContigBoundaries.size() > 0){
GS[i].setContigBoundaries(ContigBoundaries);
}
//strand-reversed case
if (GS[i].isStrRevFlipGenes() == false){
GS[i].setBarPositionsRev(barpositions);
GS[i].setContigBoundariesRev(ContigBoundaries);
} else {
//initialize output
LinkedList<Integer> revbarpositions = new LinkedList<Integer>();
LinkedList<Integer> revcontigboundaries = new LinkedList<Integer>();
for (int j = 0; j < barpositions.size(); j++){
//retrieve original bar x-position
int BarX = barpositions.get(j);
//determine dist to center
double Dist2Center = Math.abs(BarX - GS[i].getBoundingRect().getCenterX());
//determine flipped X-coordinate
int BarXFlip;
if (BarX > GS[i].getBoundingRect().getCenterX()){
BarXFlip = (int) (BarX - 2*Dist2Center - CoordinateBarWidth);
} else {
BarXFlip = (int) (BarX + 2*Dist2Center - CoordinateBarWidth);
}
//add to the output
revbarpositions.add(BarXFlip);
}
//write to output genomic segment
GS[i].setBarPositionsRev(revbarpositions);
for (int j = 0; j < ContigBoundaries.size(); j++){
//retrieve original bar x-position
int BarX = ContigBoundaries.get(j);
//determine dist to center
double Dist2Center = Math.abs(BarX - GS[i].getBoundingRect().getCenterX());
//determine flipped X-coordinate
int BarXFlip;
if (BarX > GS[i].getBoundingRect().getCenterX()){
BarXFlip = (int) (BarX - 2*Dist2Center - CoordinateBarWidth);
} else {
BarXFlip = (int) (BarX + 2*Dist2Center - CoordinateBarWidth);
}
//add to output
revcontigboundaries.add(BarXFlip);
}
//write to output genomic segment
if (revcontigboundaries.size() > 0){
GS[i].setContigBoundariesRev(revcontigboundaries);
}
}
}
}
//perform all initialization activities.
//Recalculate, redraw
public void ReComputeWithNewSegments(int BeforeValue, int AfterValue){
//set new values
this.BeforeBuffer = BeforeValue;
this.AfterBuffer = AfterValue;
//this.addMouseListener(this);
//take care of mouse-clicked info windows
if (GeneInformationIsBeingDisplayed == true){
GeneInfo.dispose();
}
this.GeneInformationIsBeingDisplayed = false;
//adjust inputs
splitCrossContigGroupings(); //Adjust contexts
splitLargeGapGroupings(); //Adjust for large gaps within groupings
//computing segment info
this.dim = computeGenomicSegments();
this.setPreferredSize(dim); //key: preferredsize, not size
//computing information for display.
computeNucleotideRangesOnSegments();
addDrawGenes();
addMotifs();
addHomologyColors();
addCoordinateBars();
}
// ------ painting components ----------------------------------------//
//paint method
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
this.setPreferredSize(dim);
draftBackgrounds(g2d); //draw background for each genomic segment
if (ShowCoordinates == true){
draftCoordinates(g2d); //draw numerical coordinates spanning genomic segment
}
draftGenes(g2d); //draw genes
if (this.mf.getFr().getPanMotifOptions().getIncludeMotifsDisp().isSelected()){
draftMotifs(g2d); //draw motifs, if desired.
}
draftLines(g2d); //draw centerline
draftLabels(g2d); //draw label associated with each genomic segment
//middle clicked genes
draftMiddleClickGenes(g2d); //draw selected homology groups
//The main frame CSD should not be altered.
//this.mf.getFr().getCurrentFrame().getInternalFrameData().getQD().setCSD(this.mf.getOriginalCSD());
//Debugging - everything showing up as blue (which is correct)
// System.out.println("paintComponent entered.");
// for (int i = 0; i < GS.length; i++){
// for (DrawGene DG : GS[i].getDg()){
// if (DG.getBioInfo().getClusterID() == 144){
// String str = "Org= "+ DG.getSourceSpecies() +
// " Contig= " + DG.getBioInfo().getContig() +
// " Color= " + DG.getColor().toString();
// System.out.println(str);
// }
// }
// }
}
//draw label associated with each genomic segment
private void draftLabels(Graphics2D g) {
for (int i = 0; i <this.GS.length; i++){
//retrieve string
String txt = GS[i].getLabel();
//create a text layout object
TextLayout tl = new TextLayout(txt,fontStandard,renderContext);
//render labels
int textX = (int) GS[i].getBoundingRect().getMinX();
int textY = (int) GS[i].getBoundingRect().getMinY() - LabelAboveGS;
tl.draw(g, textX, textY);
}
}
//draw background for each genomic segment
private void draftBackgrounds(Graphics2D g) {
g.setPaint(Color.WHITE);
//successful set the background!
//g.fillRect(0, 0, getWidth(), getHeight());
//System.out.println("width: " + getWidth() + " height: " + getHeight());
for (int i = 0; i <this.GS.length; i++){
//System.out.println("Bounding Rect: " + GS[i].getBoundingRect());
g.fill(GS[i].getBoundingRect());
}
}
//draw genes on each genomic context
private void draftGenes(Graphics2D g) {
//Debugging
//System.out.println("draftGenes.");
//add all genes to all backgrounds
for (int i = 0; i <this.GS.length; i++){
for (int j = 0; j <this.GS[i].getDg().size(); j++){
//debugging.
//DrawGene DG = GS[i].getDg().get(j);
// if (DG.getBioInfo().getClusterID() == 144){
// String str = "Org= "+ DG.getSourceSpecies() +
// " Contig= " + DG.getBioInfo().getContig() +
// " Color= " + DG.getColor().toString();
// System.out.println(str);
// }
// if (DG.getSourceSpecies().equals("CVA-1_ORF_Final") &&
// DG.getBioInfo().getStart()==90483){
// String str = "Org= "+ DG.getSourceSpecies() +
// " Contig= " + DG.getBioInfo().getContig() +
// " Color= " + DG.getColor().toString();
// System.out.println(str);
// }
//options to display some or all
if ((isShowSurrounding() == true) ||
((isShowSurrounding() == false) && (this.GS[i].getDg().get(j).getMembership() == 0))) {
//options to color extra regions
if (this.GS[i].getDg().get(j).getMembership() == 0){
//always color core genes with assigned homology color
g.setPaint(this.GS[i].getDg().get(j).getColor());
} else {
//depending on options, color light gray or original color.
if (isColorSurrounding() == true){
g.setPaint(this.GS[i].getDg().get(j).getColor());
} else {
g.setPaint(Color.LIGHT_GRAY);
}
}
//render original rectangle, or inverted strand
if (StrandNormalize == true){
//draw rectangle, with black border
g.fill(this.GS[i].getDg().get(j).getStrRevCoordinates());
//surround with black border
g.setPaint(Color.BLACK);
g.draw(this.GS[i].getDg().get(j).getStrRevCoordinates());
} else {
//draw rectangle
g.fill(this.GS[i].getDg().get(j).getCoordinates());
//surround with black border
g.setPaint(Color.BLACK);
g.draw(this.GS[i].getDg().get(j).getCoordinates());
}
}
}
}
}
//draw genes selected in click
private void draftMiddleClickGenes(Graphics2D g){
//adjust stroke
Stroke DefaultStroke = g.getStroke();
g.setStroke(new BasicStroke(6.0f));
g.setColor(Color.RED);
//color genes
if (CurrentlySelectedGeneColors != null){
for (Color c : CurrentlySelectedGeneColors){
//check all draw objects for this color.
for (int i = 0; i <GS.length; i++){
//check all genes
for (int j = 0; j <GS[i].getDg().size(); j++){
if (GS[i].getDg().get(j).getColor().equals(c)){
//normal strand case
if (StrandNormalize == false){
g.draw(this.GS[i].getDg().get(j).getCoordinates());
} else {
g.draw(this.GS[i].getDg().get(j).getStrRevCoordinates());
}
}
}
//check all motifs
for (int j = 0; j <GS[i].getDm().size(); j++){
if (GS[i].getDm().get(j).getColor().equals(c)){
if (StrandNormalize == false){
g.draw(this.GS[i].getDm().get(j).getCoordinates());
} else {
g.draw(this.GS[i].getDm().get(j).getStrRevCoordinates());
}
}
}
}
}
}
//color corresponding entries in legend
//return to default settings
g.setStroke(DefaultStroke);
g.setColor(Color.BLACK);
}
//draw center line
private void draftLines(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
for (int i = 0; i < this.GS.length; i++){
g2d.fillRect((int) GS[i].getBoundingRect().getX(), (int)Math.round(GS[i].getBoundingRect().getCenterY()),
(int) GS[i].getBoundingRect().getWidth(), GenomeLineThickness);
}
}
//draw motifs
private void draftMotifs(Graphics2D g){
//add all motifs to all backgrounds
for (int i = 0; i <this.GS.length; i++){
if (this.GS[i].getDm() != null){ //some motifs exist on this segment
for (int j = 0; j <this.GS[i].getDm().size(); j++){
//options to display some or all
if ((isShowSurrounding() == true) ||
((isShowSurrounding() == false) && (this.GS[i].getDm().get(j).getMembership() == 0))) {
//options to color extra regions
if (this.GS[i].getDm().get(j).getMembership() == 0){
//always color core genes with assigned homology color
g.setPaint(this.GS[i].getDm().get(j).getColor());
} else {
//depending on options, color light gray or original color.
if (isColorSurrounding() == true){
g.setPaint(this.GS[i].getDm().get(j).getColor());
} else {
g.setPaint(Color.LIGHT_GRAY);
}
}
//to Surround with a black border or not?
boolean SurroundWithBorder = true;
// if (g.getPaint().equals(Color.LIGHT_GRAY)){
// SurroundWithBorder = true;
// }
//currently = always
//render original ellipse, or inverted strand
if (StrandNormalize == true){
//draw ellipse
g.fill(this.GS[i].getDm().get(j).getStrRevCoordinates());
if (SurroundWithBorder){//surround with black border
g.setPaint(Color.BLACK);
g.draw(this.GS[i].getDm().get(j).getStrRevCoordinates());
}
} else {
//draw ellipse
g.fill(this.GS[i].getDm().get(j).getCoordinates());
if (SurroundWithBorder){//surround with black border
g.setPaint(Color.BLACK);
g.draw(this.GS[i].getDm().get(j).getCoordinates());
}
}
}
}
}
}
}
//draw coordinates
private void draftCoordinates(Graphics2D g){
//paint vertical bars
g.setPaint(Color.BLACK);
if (StrandNormalize == false) {
for (int i = 0; i < GS.length; i++){
g.setPaint(Color.BLACK);
//paint lines + add labels
//for (int j = GS[i].getBarPositions().size()-1; j >= 0; j--){
for (int j = 0; j < GS[i].getBarPositions().size(); j++){
g.fillRect(GS[i].getBarPositions().get(j), (int) GS[i].getBoundingRect().getMinY(),
CoordinateBarWidth, GSHeight);
//write label to appropriate place
TextLayout tl = new TextLayout(GS[i].getBarValues().get(j).toString(),fontStandard,renderContext);
tl.draw(g, GS[i].getBarPositions().get(j), (int) GS[i].getBoundingRect().getMaxY()+5);
}
//write contig boundaries
if (GS[i].getContigBoundaries() != null){
//change color
g.setPaint(Color.RED);
//paint boundaries
for (int j = 0; j <GS[i].getContigBoundaries().size(); j++){
g.fillRect(GS[i].getContigBoundaries().get(j), (int) GS[i].getBoundingRect().getMinY(),
ContigBoundaryWidth, GSHeight);
}
}
g.setPaint(Color.BLACK);
//paint a forward arrow
int[] xPoints = {(int) (GS[i].getBoundingRect().getMaxX() - ArrowLength),
(int) (GS[i].getBoundingRect().getMaxX() - ArrowLength),
(int) GS[i].getBoundingRect().getMaxX()};
int[] yPoints = {(int) GS[i].getBoundingRect().getMinY()-ArrowHeight - LabelAboveGS,
(int) GS[i].getBoundingRect().getMinY() - LabelAboveGS,
(int)(GS[i].getBoundingRect().getMinY()-(ArrowHeight/2.0) - LabelAboveGS)};
g.fillPolygon(xPoints, yPoints, 3);
//paint contig name
TextLayout t2 = new TextLayout(GS[i].getDg().get(0).getBioInfo().getContig(),fontStandard,renderContext);
//paint to panel
int ContigX = (int) GS[i].getBoundingRect().getMaxX() - ArrowLength - (int) t2.getBounds().getWidth() - 10;
int ContigY = (int) GS[i].getBoundingRect().getMinY() - LabelAboveGS;// - (int) t2.getBounds().getHeight();
t2.draw(g, ContigX, ContigY);
}
} else {
for (int i = 0; i < GS.length; i++){
g.setPaint(Color.BLACK);
//paint lines + add labels
//for (int j = GS[i].getBarPositions().size()-1; j >= 0; j--){
for (int j = 0; j < GS[i].getBarPositions().size(); j++){
g.fillRect(GS[i].getBarPositionsRev().get(j), (int) GS[i].getBoundingRect().getMinY(),
CoordinateBarWidth, GSHeight);
//write label to appropriate place
TextLayout tl = new TextLayout(GS[i].getBarValues().get(j).toString(),fontStandard,renderContext);
tl.draw(g, GS[i].getBarPositionsRev().get(j), (int) GS[i].getBoundingRect().getMaxY()+5);
}
//write contig boundaries
if (GS[i].getContigBoundariesRev() != null){
//change color
g.setPaint(Color.RED);
//paint boundaries
for (int j = 0; j <GS[i].getContigBoundariesRev().size(); j++){
g.fillRect(GS[i].getContigBoundariesRev().get(j), (int) GS[i].getBoundingRect().getMinY(),
ContigBoundaryWidth, GSHeight);
}
}
if (GS[i].isStrRevFlipGenes()){
//reverse arrows are red
g.setPaint(Color.RED);
//paint a reverse arrow
int[] xPoints = {(int) GS[i].getBoundingRect().getMaxX(),
(int) (GS[i].getBoundingRect().getMaxX()),
(int) (GS[i].getBoundingRect().getMaxX() - ArrowLength),
};
int[] yPoints = {(int)(GS[i].getBoundingRect().getMinY() - LabelAboveGS),
(int) GS[i].getBoundingRect().getMinY()-ArrowHeight - LabelAboveGS,
(int) (GS[i].getBoundingRect().getMinY()-(ArrowHeight/2.0) - LabelAboveGS),
};
g.fillPolygon(xPoints, yPoints, 3);
g.setPaint(Color.BLACK);
//paint contig name
TextLayout t2 = new TextLayout(GS[i].getDg().get(0).getBioInfo().getContig(),fontStandard,renderContext);
//paint to panel
int ContigX = (int) GS[i].getBoundingRect().getMaxX() - ArrowLength - (int) t2.getBounds().getWidth() - 10;
int ContigY = (int) GS[i].getBoundingRect().getMinY() - LabelAboveGS;// - (int) t2.getBounds().getHeight();
t2.draw(g, ContigX, ContigY);
} else {
//forward arrows are black
g.setPaint(Color.BLACK);
//paint a forward arrow
int[] xPoints = {(int) (GS[i].getBoundingRect().getMaxX() - ArrowLength),
(int) (GS[i].getBoundingRect().getMaxX() - ArrowLength),
(int) GS[i].getBoundingRect().getMaxX()};
int[] yPoints = {(int) GS[i].getBoundingRect().getMinY()-ArrowHeight - LabelAboveGS,
(int) GS[i].getBoundingRect().getMinY() - LabelAboveGS,
(int)(GS[i].getBoundingRect().getMinY()-(ArrowHeight/2.0) - LabelAboveGS)};
g.fillPolygon(xPoints, yPoints, 3);
//paint contig name
TextLayout t2 = new TextLayout(GS[i].getDg().get(0).getBioInfo().getContig(),fontStandard,renderContext);
//paint to panel
int ContigX = (int) GS[i].getBoundingRect().getMaxX() - ArrowLength - (int) t2.getBounds().getWidth() - 10;
int ContigY = (int) GS[i].getBoundingRect().getMinY() - LabelAboveGS;// - (int) t2.getBounds().getHeight();
t2.draw(g, ContigX, ContigY);
}
}
}
}
// ----- Classes + methods related to coloring -----------------------//
//class to determine counts of various objects
public class Count<K, V> extends HashMap<K, V> {
//serial ID
private static final long serialVersionUID = 1L;
// Counts unique objects
public void add(K o) {
int count = this.containsKey(o) ? ((Integer)this.get(o)).intValue() + 1 : 1;
super.put(o, (V) new Integer(count));
}
}
//transform a <String, Int> hashmap into a linked list, sorted by values
public LinkedList<SharedHomology> SortAndAddColors2Ann(HashMap<String, Integer> passedMap) {
//retrieve information, separate into appropriate keys + values
List<String> mapKeys = new ArrayList<String>(passedMap.keySet());
List<Integer> mapValues = new ArrayList<Integer>();
//retrieve values in the same order as keys
for (int i = 0; i < mapKeys.size(); i++){
mapValues.add(passedMap.get(mapKeys.get(i)));
}
//initialize output
LinkedList<SharedHomology> sortedList = new LinkedList<SharedHomology>();
//bubble sorting separate lists
for (int i = 0; i < mapValues.size()-1; i++){
for (int j = 0; j < mapValues.size()-1; j++){
//switch, if possible
if (mapValues.get(j) < mapValues.get(j+1)){
//store variables in temp
int tempInt = mapValues.get(j);
String tempString = mapKeys.get(j);
//substitute variables
mapValues.set(j, mapValues.get(j+1));
mapKeys.set(j, mapKeys.get(j+1));
//replace temp
mapValues.set(j+1, tempInt);
mapKeys.set(j+1, tempString);
}
}
}
//import a color map
Color[] c2 = {new Color(255,0,0),new Color(255,255,255),new Color(0,0,255)};
//add to output list
for (int i = 0; i < mapValues.size(); i++){
SharedHomology SH = new SharedHomology();
SH.setAnnotation(mapKeys.get(i));
SH.setFrequency(mapValues.get(i));
SH.setOffSetPoint(OffSetPoint);
SH.addColor(i);
SH.setECRONType("annotation");
sortedList.add(SH);
}
//return list
return sortedList;
}
//transform a <Int, Int> hashmap into a linked list, sorted by values
private LinkedList<SharedHomology> SortAndAddColors2Cluster(HashMap<Integer, Integer> passedMap) {
//retrieve information, separate into appropriate keys + values
List<Integer> mapKeys = new ArrayList<Integer>(passedMap.keySet());
List<Integer> mapValues = new ArrayList<Integer>();
//retrieve values in the same order as keys
for (int i = 0; i < mapKeys.size(); i++){
mapValues.add(passedMap.get(mapKeys.get(i)));
}
//initialize output
LinkedList<SharedHomology> sortedList = new LinkedList<SharedHomology>();
//bubble sorting separate lists
for (int i = 0; i < mapValues.size()-1; i++){
for (int j = 0; j < mapValues.size()-1; j++){
//switch, if possible
if (mapValues.get(j) < mapValues.get(j+1)){
//store variables in temp
int tempInt = mapValues.get(j);
int tempCluster = mapKeys.get(j);
//substitute variables
mapValues.set(j, mapValues.get(j+1));
mapKeys.set(j, mapKeys.get(j+1));
//replace temp
mapValues.set(j+1, tempInt);
mapKeys.set(j+1, tempCluster);
}
}
}
//add to output list
for (int i = 0; i < mapValues.size(); i++){
SharedHomology SH = new SharedHomology();
SH.setClusterID(mapKeys.get(i));
SH.setFrequency(mapValues.get(i));
SH.setOffSetPoint(OffSetPoint);
SH.addColor(i);
SH.setECRONType("cluster");
sortedList.add(SH);
}
//return list
return sortedList;
}
// ---- Warning Messages -------------------------------------- //
//contexts with overly large gene groupings are not displayed
private void showExludedContexts(){
String Msg = "The following nodes refer to a genomic grouping of size " + RangeLimit + " nt or more,\n";
Msg = Msg + "and so are not displayed:\n";
for (String s: ExceededRangeLimit){
Msg = Msg + s + "\n";
}
JOptionPane.showMessageDialog(null, Msg, "Gene Grouping Size Limit Exceeded", JOptionPane.INFORMATION_MESSAGE);
}
// ---- Genome Display Options -------------------------------------- //
public boolean isShowSurrounding() {
return ShowSurrounding;
}
public void setShowSurrounding(boolean showSurrounding) {
ShowSurrounding = showSurrounding;
}
public boolean isColorSurrounding() {
return ColorSurrounding;
}
public void setColorSurrounding(boolean colorSurrounding) {
ColorSurrounding = colorSurrounding;
}
public boolean isStrandNormalize() {
return StrandNormalize;
}
public void setStrandNormalize(boolean strandNormalize) {
StrandNormalize = strandNormalize;
}
public boolean isShowCoordinates() {
return ShowCoordinates;
}
public void setShowCoordinates(boolean showCoordinates) {
ShowCoordinates = showCoordinates;
}
public int getCoordinateBarEvery() {
return CoordinateBarEvery;
}
public void setCoordinateBarEvery(int coordinateBarEvery) {
CoordinateBarEvery = coordinateBarEvery;
}
public JFrame getGeneInfo() {
return GeneInfo;
}
// ----- Mouse Click info -------------------------------------------//
public LinkedList<SharedHomology> getGeneList() {
return GeneColorList;
}
public void setGeneList(LinkedList<SharedHomology> geneList) {
GeneColorList = geneList;
}
public GeneColorLegendFrame getGclf() {
return gclf;
}
public void setGclf(GeneColorLegendFrame gclf) {
this.gclf = gclf;
}
public boolean isClickedOnLegend() {
return ClickedOnLegend;
}
public void setClickedOnLegend(boolean clickedOnLegend) {
ClickedOnLegend = clickedOnLegend;
}
public LinkedList<Color> getCurrentlySelectedGeneColors() {
return CurrentlySelectedGeneColors;
}
public void setCurrentlySelectedGeneColors(
LinkedList<Color> currentlySelectedGeneColors) {
CurrentlySelectedGeneColors = currentlySelectedGeneColors;
}
@Override
public void mouseClicked(MouseEvent e) {
//left click: genomic information
if(SwingUtilities.isLeftMouseButton(e)){
//recover clicked draw gene
DrawObject NewlyClicked = FindCurrentDrawObject(e);
//null case (no gene clicked): release all.
if (NewlyClicked == null){
//close current information frame, if it exists.
if (GeneInfo != null){
GeneInfo.dispose();
}
GeneInformationIsBeingDisplayed = false;
//current gene case: release all.
} else if (NewlyClicked == CurrentLeftClickedDrawObject){
// update
if (GeneInformationIsBeingDisplayed){
//close current information frame, if it exists.
if (GeneInfo != null){
GeneInfo.dispose();
GeneInformationIsBeingDisplayed = false;
}
} else {
//create new frame
JFrame Info = MakeGeneInfo(e);
//bring to front
Info.toFront();
this.repaint();
//set JFrame to the field.
this.GeneInfo = Info;
GeneInformationIsBeingDisplayed = true;
}
//new location case: assign current clicked here.
} else {
//close current information frame, if it exists.
if (GeneInfo != null){
GeneInfo.dispose();
}
CurrentLeftClickedDrawObject = NewlyClicked;
//create new frame
JFrame Info = MakeGeneInfo(e);
//bring to front
Info.toFront();
this.repaint();
//set JFrame to the field.
this.GeneInfo = Info;
GeneInformationIsBeingDisplayed = true;
}
//update graphical display
this.repaint();
//right click: export menu
} else if (SwingUtilities.isRightMouseButton(e)){
//check moduls.frm.children -> Frmpiz ->.initComponentsMenu() <201>
//update place clicked
this.PlaceClicked = e.getPoint();
//trigger pop-up menu display
this.ExportMenu.show(e.getComponent(),
e.getXOnScreen(), e.getYOnScreen());
//reposition appropriately
this.ExportMenu.setLocation(e.getXOnScreen(),e.getYOnScreen());
//center click: select all by common homology
} else if (SwingUtilities.isMiddleMouseButton(e)){
//recover clicked draw gene
DrawObject NewlyClicked = FindCurrentDrawObject(e);
//null case (no gene clicked): release all.
if (NewlyClicked == null){
//reset all colors
CurrentlySelectedGeneColors = new LinkedList<Color>();
CurrentMiddleClickedDrawObject = null;
//new location case: assign current clicked here.
} else {
//new location
CurrentMiddleClickedDrawObject = NewlyClicked;
//check for shift/ctrl buttons
if (e.isShiftDown() || e.isControlDown()){
//check and see if this is in the existing list.
boolean AlreadyInTheList = false;
if (CurrentlySelectedGeneColors != null){
for (Color c : CurrentlySelectedGeneColors){
if (CurrentMiddleClickedDrawObject.getColor().equals(c)){
AlreadyInTheList = true;
}
}
if (AlreadyInTheList){
CurrentlySelectedGeneColors.remove((Color) CurrentMiddleClickedDrawObject.getColor());
} else {
//add to existing list
CurrentlySelectedGeneColors.add((Color) CurrentMiddleClickedDrawObject.getColor());
}
} else {
//initialize a new list with a single entry.
this.CurrentlySelectedGeneColors = new LinkedList<Color>();
CurrentlySelectedGeneColors.add((Color) CurrentMiddleClickedDrawObject.getColor());
}
} else {
//replace existing list with single entry
this.CurrentlySelectedGeneColors = new LinkedList<Color>();
CurrentlySelectedGeneColors.add((Color) CurrentMiddleClickedDrawObject.getColor());
}
}
//update list in legend panel, if it exists.
if (this.gclp != null){
//LinkedList<SharedHomology> UpdatedLegendColors = new LinkedList<SharedHomology>();
boolean[] UpdatedSelectedRectangles = new boolean[gclp.getSelectedRectangles().length];
Arrays.fill(UpdatedSelectedRectangles,false);
for (Color c : CurrentlySelectedGeneColors){
for (int i = 0; i < UpdatedSelectedRectangles.length; i++){
if (gclp.getGeneList()[i].getColor().equals(c)){
UpdatedSelectedRectangles[i] = true;
}
}
}
this.gclp.setSelectedRectangles(UpdatedSelectedRectangles);
this.gclp.repaint();
}
//update graphical display
this.repaint();
//bring gene tags to center
if (this.GeneInfo != null){
this.GeneInfo.toFront();
}
}
}
//Determine the identity of the clicked on gene.
private DrawObject FindCurrentDrawObject(MouseEvent e) {
DrawObject SelectedObject = null;
//Check for a gene in the selected area.
for (int i = 0; i <GS.length; i++){
for (int j = 0; j <GS[i].getDg().size(); j++){
//normal strand case
if (StrandNormalize == false){
if (GS[i].getDg().get(j).getCoordinates().contains(e.getPoint())){
SelectedObject = GS[i].getDg().get(j);
break;
}
} else {
if (GS[i].getDg().get(j).getStrRevCoordinates().contains(e.getPoint())){
SelectedObject = GS[i].getDg().get(j);
break;
}
}
}
}
//Check for a motif - precedence over genes
for (int i = 0; i < GS.length; i++){
for (int j = 0; j < GS[i].getDm().size(); j++){
if (StrandNormalize == false){
if (GS[i].getDm().get(j).getCoordinates().contains(e.getPoint())){
SelectedObject = GS[i].getDm().get(j);
break;
}
} else {
if (GS[i].getDm().get(j).getStrRevCoordinates().contains(e.getPoint())){
SelectedObject = GS[i].getDm().get(j);
break;
}
}
}
}
//return the current object
return SelectedObject;
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public JFrame MakeGeneInfo(MouseEvent e){
//create new frame
JFrame Info = new JFrame();
Info.setUndecorated(true);
Info.setBackground(Color.YELLOW);
Info.setLocation((int)MouseInfo.getPointerInfo().getLocation().getX()+1,(int)MouseInfo.getPointerInfo().getLocation().getY()+1);
//compute + import text to display
JTextPanewLineNumbers txtToDisplay = ComputeJTextField(e);
if (txtToDisplay.getText().equals("")){
Info.setVisible(false);
} else {
Info.setVisible(true);
}
//Create JPanel
JPanel jp = new JPanel();
jp.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.insets = new Insets(1,1,1,1);
jp.add(txtToDisplay, c);
//wrap jpanel around scroll pane
JScrollPane scrpan = new JScrollPane(jp);
//size details
scrpan.setPreferredSize(new Dimension(1000,400));
Info.setSize(new Dimension(250,txtToDisplay.getNumberOfLines()*18));
Info.add(scrpan);
jp.setBackground(Color.YELLOW);
return Info;
}
public JTextPanewLineNumbers ComputeJTextField(MouseEvent e){
//determine number of headers/footers etc
int NumberToInclude = 0;
boolean Options[] = new boolean[6];
String[] OptionNames = {"Annotation:\n","ClusterID:","Size:","Start:","Stop:","Type:"};
//1
if (mf.getOp().getCbAnnotation().isSelected()){
NumberToInclude++;
this.ShowAnnotation = true;
} else {
this.ShowAnnotation = false;
}
Options[0] = this.ShowAnnotation;
//2
if (mf.getOp().getCbClusterID().isSelected()){
NumberToInclude++;
this.ShowClusterID = true;
} else {
this.ShowClusterID = false;
}
Options[1] = this.ShowClusterID;
//3
if (mf.getOp().getCbSize().isSelected()){
NumberToInclude++;
this.ShowSize = true;
} else {
this.ShowSize = false;
}
Options[2] = this.ShowSize;
//4
if (mf.getOp().getCbStart().isSelected()){
NumberToInclude++;
this.ShowStart = true;
} else {
this.ShowStart = false;
}
Options[3] = this.ShowStart;
//5
if (mf.getOp().getCbStop().isSelected()){
NumberToInclude++;
this.ShowStop = true;
} else
this.ShowStop = false;
Options[4] = this.ShowStop;
//6
if (mf.getOp().getCbType().isSelected()){
NumberToInclude++;
this.ShowType = true;
} else {
this.ShowType = false;
}
Options[5] = this.ShowType;
//JTextField computation
String[] Headers = new String[NumberToInclude];
String[] Values = new String[NumberToInclude];
//number of lines
int NumberOfLines = 1;
//find the gene in the selected area.
for (int i = 0; i <GS.length; i++){
for (int j = 0; j <GS[i].getDg().size(); j++){
//natural strand case
if (StrandNormalize == false){
if (GS[i].getDg().get(j).getCoordinates().contains(e.getPoint())){
//re-set count for appropriate sizing.
NumberOfLines = 1;
int Counter = 0;
for (int k = 0; k <Options.length; k++){
if (Options[k] == true){
//write option name
Headers[Counter] = OptionNames[k];
String EntryString;
//retrieve the stored value
if (k == 0){
//format string into multiple lines
String TheAnnotation = GS[i].getDg().get(j).getBioInfo().getAnnotation();
String[] SegmentedAnnotation = TheAnnotation.split(" ");
//counters
int WordCounter = 0;
NumberOfLines++;
//line for entry
String EntryLine = ""; EntryString = "";
Boolean FirstWordOfLine = true;
// System.out.println(TheAnnotation);
//while words still remain
while (WordCounter < SegmentedAnnotation.length){
//build the line
while (EntryLine.length() < CharacterMax && WordCounter < SegmentedAnnotation.length){
if (FirstWordOfLine == true){
EntryLine = SegmentedAnnotation[WordCounter];
FirstWordOfLine = false;
} else {
EntryLine = EntryLine + " " + SegmentedAnnotation[WordCounter];
}
// System.out.println("word: " + SegmentedAnnotation[WordCounter]);
// System.out.println("line: " + EntryLine);
WordCounter++;
}
//System.out.println(EntryLine);
//add to existing set, and add new line.
EntryString = EntryString + EntryLine + "\n";
EntryLine = "";
FirstWordOfLine = true;
NumberOfLines++;
}
// System.out.println("out of the while loop!");
// System.out.println(EntryString);
} else if (k == 1){
int TheCluster = GS[i].getDg().get(j).getBioInfo().getClusterID();
if (TheCluster == 0){
EntryString = "none";
} else {
EntryString = Integer.toString(TheCluster);
}
} else if (k == 2) {
EntryString = Integer.toString((GS[i].getDg().get(j).getBioInfo().getStop()
-GS[i].getDg().get(j).getBioInfo().getStart()+1)) + " nt";
} else if (k == 3) {
EntryString = Integer.toString(GS[i].getDg().get(j).getBioInfo().getStart());
} else if (k == 4) {
EntryString = Integer.toString(GS[i].getDg().get(j).getBioInfo().getStop());
} else {
EntryString = GS[i].getDg().get(j).getBioInfo().getType();
}
//add a new line after the entry.
if (k != 0){
Values[Counter] = " " + EntryString + "\n";
NumberOfLines++;
} else {
Values[Counter] = " " + EntryString;
}
//increment counter
Counter++;
}
}
}
//corrected strand case
} else {
if (GS[i].getDg().get(j).getStrRevCoordinates().contains(e.getPoint())){
//re-set count for appropriate sizing.
NumberOfLines = 1;
int Counter = 0;
for (int k = 0; k <Options.length; k++){
if (Options[k] == true){
//write option name
Headers[Counter] = OptionNames[k];
String EntryString;
//retrieve the stored value
if (k == 0){
//format string into multiple lines
String TheAnnotation = GS[i].getDg().get(j).getBioInfo().getAnnotation();
String[] SegmentedAnnotation = TheAnnotation.split(" ");
//counters
int WordCounter = 0;
NumberOfLines++;
//line for entry
String EntryLine = ""; EntryString = "";
Boolean FirstWordOfLine = true;
//while words still remain
while (WordCounter < SegmentedAnnotation.length){
//build the line
while (EntryLine.length() < CharacterMax && WordCounter < SegmentedAnnotation.length){
if (FirstWordOfLine == true){
EntryLine = SegmentedAnnotation[WordCounter];
FirstWordOfLine = false;
} else {
EntryLine = EntryLine + " " + SegmentedAnnotation[WordCounter];
}
WordCounter++;
}
//System.out.println(EntryLine);
//add to existing set, and add new line.
EntryString = EntryString + EntryLine + "\n";
EntryLine = "";
FirstWordOfLine = true;
NumberOfLines++;
}
} else if (k == 1){
int TheCluster = GS[i].getDg().get(j).getBioInfo().getClusterID();
if (TheCluster == 0){
EntryString = "none";
} else {
EntryString = Integer.toString(TheCluster);
}
} else if (k == 2) {
EntryString = Integer.toString((GS[i].getDg().get(j).getBioInfo().getStop()
-GS[i].getDg().get(j).getBioInfo().getStart()+1)) + " nt";
} else if (k == 3) {
EntryString = Integer.toString(GS[i].getDg().get(j).getBioInfo().getStart());
} else if (k == 4) {
EntryString = Integer.toString(GS[i].getDg().get(j).getBioInfo().getStop());
} else {
EntryString = GS[i].getDg().get(j).getBioInfo().getType();
}
//add a new line after the entry.
if (k != 0){
Values[Counter] = " " + EntryString + "\n";
NumberOfLines++;
} else {
Values[Counter] = " " + EntryString;
}
//increment counter
Counter++;
}
}
}
}
}
//check for motifs
if (GS[i].getDm() != null){
//System.out.println("Clicked a motif");
for (int j = 0; j <GS[i].getDm().size(); j++){
//natural strand case
if (StrandNormalize == false){
if (GS[i].getDm().get(j).getCoordinates().contains(e.getPoint())){
//re-set count for appropriate sizing.
NumberOfLines = 1;
int MotifCounter = 0;
for (int k = 0; k <Options.length; k++){
if (Options[k] == true){
//Headers
Headers[MotifCounter] = OptionNames[k];
String EntryString;
if (k == 0){
Headers[MotifCounter] = "Motif:";
EntryString = GS[i].getDm().get(j).getBioInfo().getMotifName();
} else if (k == 1) {
Headers[MotifCounter] = "Sequence:";
EntryString = GS[i].getDm().get(j).getBioInfo().getSequence();
} else if (k == 2){
EntryString = Integer.toString((GS[i].getDm().get(j).getBioInfo().getStop()
-GS[i].getDm().get(j).getBioInfo().getStart()+1)) + " nt";
} else if (k == 3) {
EntryString = Integer.toString(GS[i].getDm().get(j).getBioInfo().getStart());
} else if (k == 4) {
EntryString = Integer.toString(GS[i].getDm().get(j).getBioInfo().getStop());
} else {
Headers[MotifCounter] = "Source:";
EntryString = GS[i].getDm().get(j).getBioInfo().getSource();
}
//increment Counter + write info
Values[MotifCounter] = " " + EntryString + "\n";
NumberOfLines++;
MotifCounter++;
}
}
}
} else {
if (GS[i].getDm().get(j).getStrRevCoordinates().contains(e.getPoint())){
//re-set count for appropriate sizing.
NumberOfLines = 1;
int MotifCounter = 0;
for (int k = 0; k <Options.length; k++){
if (Options[k] == true){
//Headers
Headers[MotifCounter] = OptionNames[k];
String EntryString;
if (k == 0){
Headers[MotifCounter] = "Motif:";
EntryString = GS[i].getDm().get(j).getBioInfo().getMotifName();
} else if (k ==1) {
Headers[MotifCounter] = "Sequence:";
EntryString = GS[i].getDm().get(j).getBioInfo().getSequence();
} else if (k == 2){
EntryString = Integer.toString((GS[i].getDm().get(j).getBioInfo().getStop()
-GS[i].getDm().get(j).getBioInfo().getStart()+1)) + " nt";
} else if (k == 3) {
EntryString = Integer.toString(GS[i].getDm().get(j).getBioInfo().getStart());
} else if (k == 4) {
EntryString = Integer.toString(GS[i].getDm().get(j).getBioInfo().getStop());
} else {
Headers[MotifCounter] = "Source:";
EntryString = GS[i].getDm().get(j).getBioInfo().getSource();
}
//increment Counter + write info
Values[MotifCounter] = " " + EntryString + "\n";
NumberOfLines++;
MotifCounter++;
}
}
}
}
}
}
}
// create a JTextPane + add settings
JTextPanewLineNumbers jtp = new JTextPanewLineNumbers();
jtp.setEditable(false);
jtp.setBackground(Color.YELLOW);
//retrieve document, and add styles
StyledDocument doc = jtp.getStyledDocument();
Style def = StyleContext.getDefaultStyleContext().
getStyle(StyleContext.DEFAULT_STYLE);
Style regular = doc.addStyle("regular", def);
StyleConstants.setFontFamily(def, "SansSerif");
Style s = doc.addStyle("bold", regular);
StyleConstants.setBold(s, true);
//write styles
for (int i=0; i <Headers.length; i++) {
try {
doc.insertString(doc.getLength(), Headers[i], doc.getStyle("bold"));
doc.insertString(doc.getLength(), Values[i], doc.getStyle("regular"));
} catch (BadLocationException e1) {
System.out.println("bad location exception");
}
}
//note information to compute size
jtp.setNumberOfLines(NumberOfLines);
jtp.setCharacterWidthLimit(CharacterMax);
//return computed JTextfield
return jtp;
}
class JTextPanewLineNumbers extends JTextPane{
//serial ID
private static final long serialVersionUID = 1L;
private int CharacterWidthLimit;
private int NumberOfLines;
public int getCharacterWidthLimit() {
return CharacterWidthLimit;
}
public void setCharacterWidthLimit(int characterWidthLimit) {
CharacterWidthLimit = characterWidthLimit;
}
public int getNumberOfLines() {
return NumberOfLines;
}
public void setNumberOfLines(int numberOfLines) {
NumberOfLines = numberOfLines;
}
}
public LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>> getSplitContexts() {
return SplitContexts;
}
public void setSplitContexts(
LinkedHashMap<String, LinkedList<GenomicElementAndQueryMatch>> splitContexts) {
SplitContexts = splitContexts;
}
public LinkedHashMap<String, String> getSplitSpeciesNames() {
return SplitSpeciesNames;
}
public void setSplitSpeciesNames(LinkedHashMap<String, String> splitSpeciesNames) {
SplitSpeciesNames = splitSpeciesNames;
}
public LinkedHashMap<String, HashSet<String>> getSplitContigNames() {
return SplitContigNames;
}
public void setSplitContigNames(LinkedHashMap<String, HashSet<String>> splitContigNames) {
SplitContigNames = splitContigNames;
}
}