package statalign.postprocess.gui;
import javax.swing.*;
import org.apache.commons.math3.util.Pair;
import java.awt.*;
import statalign.model.subst.SubstitutionModel;
import statalign.postprocess.Postprocess;
import statalign.postprocess.Track;
/**
* This is the graphical interface for showing alignments.
*
* @author miklos,novak
*
*/
public class AlignmentGUI extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
// JPanel pan;
// CurrentAlignment owner;
SubstitutionModel subst;
Postprocess owner = null;
/**
* The alignment that is written onto the screen is stored in this array
*/
public String[] alignment = null;
public String[] sequenceNames = null;
/**
* The title of the current analysis
*/
public String title;
/**
* These are the posterior decoding values
*/
public double[] decoding = null;
private int aligNum = 15;
private int aligLen = 200;
/** Values greater than SCALE_FACTOR * mean will be cropped */
static double SCALE_FACTOR = 2.5;
static final int COLUMN_WIDTH = 9;
static final int FONT_HEIGHT = 15;
static final int OFFSET_X = 10;
static final int OFFSET_Y = 10;
static final int TITLE_Y = 20;
//static final String magentaCharacters = "RHK";
//static final String redCharacters = "AVFPMILW";
//static final String blueCharacters = "DE";
//static final String greenCharacters = "STYCNGQ";
/**
* It initializes a new panel for alignments.
*
* @param title This is the title of the current analysis
* @param subst The substitution model defines the background colors of characters
*/
public AlignmentGUI(String title, SubstitutionModel subst) {//CurrentAlignment inp, String[] s){
// String a = "";
// for(int i = 0; i < s.length; i++){
// a += s[i]+"\n";
// }
// this.pan = pan;
// this.owner = inp;
this.title = title;
this.subst = subst;
}
/**
* It initializes a new panel for alignments.
*
* @param title This is the title of the current analysis
* @param subst The substitution model defines the background colors of characters
* @param _owner The Postprocess plugin that owns this GUI.
*/
public AlignmentGUI(String title, SubstitutionModel subst, Postprocess _owner) {//CurrentAlignment inp, String[] s){
// String a = "";
// for(int i = 0; i < s.length; i++){
// a += s[i]+"\n";
// }
// this.pan = pan;
// this.owner = inp;
this.title = title;
this.subst = subst;
owner = _owner;
}
// private static boolean allTab(String[] s, int p){
// boolean b = true;
// for(int i = 0; i < s.length && b; i++){
// b = s[i].charAt(p) == '\t';
// }
// return b;
// }
/**
* This function updates the graphics
*/
public void paintComponent(Graphics gr){
// System.out.println("Updating current alignment");
// super.paintComponent(gr);
//System.out.println("Updating current alignment");
double maxScore = 1.0;
//setSize((int)(owner.pan.getSize().width*0.9),(int)(owner.pan.getSize().height*0.9));
// text.setRows(pan.getHeight()/13);
// text.setColumns((int)(pan.getWidth()/6.6));
if(alignment != null){
// text.replaceRange(owner.alignment, 0, length);
//length = owner.alignment.length();
}
Graphics2D g = (Graphics2D)gr;
g.setBackground(Color.WHITE);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
// alignment = owner.allAlignment;
// title = owner.title;
if(alignment != null && alignment[0] != null) {
//int colHeight = (decoding == null ? 0 : Math.min(200, g.getClipBounds().height - (2 * OFFSET_Y + TITLE_Y + alignment.length * FONT_HEIGHT)));
// Changed this to fixed height:
boolean extraTracks = owner != null && owner.getTracks() != null && owner.getTracks().size() > 0;
int colHeight = ((decoding == null && !extraTracks) ? 0 : 130);
int maxNameLength = 0;
aligNum = alignment.length;
for (int i=0; i<aligNum; i++) {
//System.out.println(sequenceNames[i]+"...");
int l = sequenceNames[i].length();
if (l > 0) {
maxNameLength = (l > maxNameLength) ? l : maxNameLength;
}
}
aligLen = alignment[0].length() + maxNameLength + 5;
setSize(OFFSET_X + COLUMN_WIDTH * aligLen + 30, OFFSET_Y + TITLE_Y + FONT_HEIGHT * aligNum+30);
//Find the maximum length of the sequence names
// int[] nameLength = new int[alignment.length];
// int maxSeqNameLength = 0;
// for (int i=0; i<alignment.length; i++) {
// int j=0;
// while(alignment[i].charAt(j++) != '\t') { nameLength[i] = j + 1; }
// maxSeqNameLength = j > maxSeqNameLength ? j : maxSeqNameLength;
// }
// int maxSNL = maxSeqNameLength; // Shorthand
// int tab =alignment[0].length()-2;
// while(!allTab(alignment, tab)){
// tab--;
// }
//System.out.println("Tab: "+tab);
g.setColor(Color.BLACK);
g.setFont(new Font("SANS_SERIF", Font.BOLD, 16));
//g.drawString(title, OFFSET_X, TITLE_Y);
g.setFont(new Font("MONOSPACED", Font.PLAIN, 12));
// g.setClip(0,0, COLUMN_WIDTH * alignment[0].length() + 2 * OFFSET_X, g.getClipBounds().height);
for (int i = 0; i < alignment.length; i++) {
//System.out.println(alignment[i]);
g.drawString(sequenceNames[i],OFFSET_X,colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * (i+1));
// if (sequenceNames[i].length() < maxNameLength) {
// for (int j=0; j<maxNameLength-sequenceNames[i].length(); j++) {
// g.drawString(' ',OFFSET_X + COLUMN_WIDTH * j);
// }
// }
// System.out.println("i = "+i+", maxNameLength = "+maxNameLength);
for (int j = 0; j < alignment[i].length(); j++) {
char ch = alignment[i].charAt(j);
// int jOffset = j;
// if (j==nameLength[i]) {
// jOffset = maxSNL;
// }
// if (j>=maxNameLength){
g.setColor(subst.getColor(ch));
g.fillRect(OFFSET_X + COLUMN_WIDTH * (j+maxNameLength),
colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * i + 3,
COLUMN_WIDTH,
FONT_HEIGHT);
//System.out.println((OFFSET_X + COLUMN_WIDTH * j)+" "+(colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * i + 3));
//}
g.setColor(Color.BLACK);
g.drawString(ch + "",
OFFSET_X + COLUMN_WIDTH * (j+maxNameLength),
colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * (i+1));
}
}
if(decoding != null){
// System.out.println(decoding[1]);
//System.out.println("Printing decoding.");
Track decodingTrack = new Track(Color.BLUE,decoding,1,0,1);
plotScore(g,decodingTrack,maxNameLength,colHeight);
}
if (extraTracks) {
//System.out.println("Printing "+owner.getTracks().size()+" extra track(s).");
for (Track track : owner.getTracks()) {
plotScore(g,track,maxNameLength,colHeight);
}
}
}
else{
g.setColor(Color.BLACK);
g.setFont(new Font("SANS_SERIF", Font.BOLD, 16));
g.drawString("Waiting for data...", OFFSET_X, TITLE_Y);
}
// this.updateUI();
}
private void plotScore(Graphics2D g, Track track, int maxNameLength, int colHeight) {
//int colHeight = Math.min(100, g.getClipBounds().height - (2 * OFFSET_Y + TITLE_Y + alignment.length * FONT_HEIGHT));
//System.out.println("Score length = "+score.length);
Color oldColor = g.getColor();
g.setColor(track.color);
double maxScore = track.max;
if (maxScore > SCALE_FACTOR * track.mean) maxScore = SCALE_FACTOR * track.mean;
for(int i = 1; i < track.scores.length; i++){
//System.out.println(track.scores[i-1]);
if (Double.isNaN(track.scores[i-1])) { continue; }
if (Double.isNaN(track.scores[i])) { ++i; continue; }
g.drawLine( OFFSET_X + (maxNameLength + i - 1) * COLUMN_WIDTH + COLUMN_WIDTH / 2,
(int)(OFFSET_Y + TITLE_Y + colHeight - Math.round(track.scores[i-1] * (colHeight) / maxScore)),
// (int)(OFFSET_Y + TITLE_Y - Math.round(decoding[i-1] * (TITLE_Y) / max)),
OFFSET_X + (maxNameLength + i) * COLUMN_WIDTH + COLUMN_WIDTH / 2,
(int)(OFFSET_Y + TITLE_Y + colHeight - Math.round(track.scores[i] * (colHeight) / maxScore))
// (int)(OFFSET_Y + TITLE_Y - Math.round(decoding[i] * (TITLE_Y) / max))
);
}
g.setColor(oldColor);
}
/**
* This function tells the minimum size of the panel
*/
public Dimension getMinimumSize(){
return getPreferredSize();
}
/**
* This function tells the preferred size of the panel
*/
public Dimension getPreferredSize() {
return new Dimension(OFFSET_X + COLUMN_WIDTH * aligLen + 30, OFFSET_Y + TITLE_Y + FONT_HEIGHT * aligNum+30);
// if (alignment != null && alignment[0] != null) {
// return new Dimension((alignment[0].length() + 3) * COLUMN_WIDTH + 6 * OFFSET_X, 100);
// } else {
// return new Dimension(0,100);
// }
}
}
/*
package statalign.postprocess.gui;
import java.text.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import javax.swing.*;
import statalign.postprocess.plugins.CurrentAlignment;
public class CurrentAlignmentGUI extends JPanel{
CurrentAlignment currentAlignment;
JPanel panel;
public JTextArea text;
public CurrentAlignmentGUI(JPanel panel, CurrentAlignment currentAlignment) {
this.currentAlignment = currentAlignment;
this.panel = panel;
text = new JTextArea(20,20);
}
private String[] alignment = null;
private String title;
private int numCols;
private int numRows;
static final int COLUMN_WIDTH = 9;
static final int FONT_HEIGHT = 15;
static final int OFFSET_X = 10;
static final int OFFSET_Y = 10;
static final int TITLE_Y = 20;
static final String magentaCharacters = "RHK";
static final String redCharacters = "AVFPMILW";
static final String blueCharacters = "DE";
static final String greenCharacters = "STYCNGQ";
public CurrentAlignmentGUI() {
}
public void updateData(String[] alignment, String title) {
this.alignment = alignment;
this.title = title;
numCols = alignment[0].length() + 1;
numRows = alignment.length;
}
public void paintComponent(Graphics gr){
super.paintComponent(gr);
text.setColumns((int)(panel.getWidth()/6.6));
text.setRows(panel.getHeight()/13);
}
/*
public void paintComponent(Graphics gr) {
System.out.println("Updating current alignment");
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr.create();
g.setBackground(Color.WHITE);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
alignment = currentAlignment.alignment;
if(alignment != null) {
int colHeight = Math.min(100, g.getClipBounds().height - (2 * OFFSET_Y + TITLE_Y + numRows * FONT_HEIGHT));
// double max = 1;
//for (int i = 0; i < numCols; i++) {
//max = Math.max(max, rs.getValue(i));
// }
//System.out.println("Maximum "+max);
// g.setColor(Color.LIGHT_GRAY);
// for (int i = 0; i < 5; i++) {
//g.drawLine( OFFSET_X+24*COLUMN_WIDTH,
// OFFSET_Y + TITLE_Y + Math.round(i * (float)colHeight / 4),
// OFFSET_X + numCols * COLUMN_WIDTH,
//OFFSET_Y + TITLE_Y + Math.round(i * (float)colHeight / 4));
//}
g.setColor(Color.BLACK);
g.setFont(new Font("SANS_SERIF", Font.BOLD, 16));
g.drawString(title, OFFSET_X, TITLE_Y);
g.setFont(new Font("MONOSPACED", Font.PLAIN, 12));
g.setClip(0,0, COLUMN_WIDTH * numCols + 2 * OFFSET_X, g.getClipBounds().height);
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < alignment[i].length(); j++) {
if(j>23){
g.setColor(Color.LIGHT_GRAY);
if(magentaCharacters.indexOf(alignment[i].charAt(j)) != -1){
g.setColor(Color.MAGENTA);
}
else if(redCharacters.indexOf(alignment[i].charAt(j)) != -1){
g.setColor(Color.RED);
}
else if(blueCharacters.indexOf(alignment[i].charAt(j)) != -1){
g.setColor(Color.BLUE);
}
else if(greenCharacters.indexOf(alignment[i].charAt(j)) != -1){
g.setColor(Color.GREEN);
}
g.fillRect(OFFSET_X + COLUMN_WIDTH * i,colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * j + 3,COLUMN_WIDTH,FONT_HEIGHT);
}
g.setColor(Color.BLACK);
g.drawString(alignment[i].charAt(j) + "",
OFFSET_X + COLUMN_WIDTH * j,
colHeight + OFFSET_Y + TITLE_Y + FONT_HEIGHT * (i+1));
}
}
}
// if(i>24){
// g.setColor(Color.BLUE);
// g.drawLine( OFFSET_X + (j - 1) * COLUMN_WIDTH + COLUMN_WIDTH / 2,
// (int)(OFFSET_Y + TITLE_Y + colHeight - Math.round(rs.getValue(j-1) * (colHeight) / max)),
//OFFSET_X + j * COLUMN_WIDTH + COLUMN_WIDTH / 2,
// (int)(OFFSET_Y + TITLE_Y + colHeight - Math.round(rs.getValue(j) * (colHeight) / max))
// );
// }
// }
//}
this.updateUI();
}
public Dimension getMinimumSize(){
return getPreferredSize();
}
public Dimension getPreferredSize() {
if (alignment != null) {
return new Dimension((alignment[0].length() + 3) * COLUMN_WIDTH, 100);
} else {
return new Dimension(0,100);
}
}
}
*/