package org.seqcode.viz.metaprofile.swing; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFileChooser; import javax.swing.JPanel; import org.seqcode.viz.metaprofile.BinningParameters; import org.seqcode.viz.metaprofile.Profile; import org.seqcode.viz.metaprofile.ProfilePaintable; import org.seqcode.viz.paintable.PaintableChangedEvent; import org.seqcode.viz.paintable.PaintableChangedListener; import org.seqcode.viz.paintable.PaintableScale; public class MultiProfilePanel extends JPanel implements PaintableChangedListener { private List<Profile> profiles; private List<ProfilePaintable> profilePainters = new ArrayList<ProfilePaintable>(); private PaintableScale scale; private int fontSize=12; private int border=20; private int lineHeight=20, lineWidth=4; private Color fontColor=Color.black; private Color[] peakColors={Color.blue, Color.red, Color.gray, Color.green, Color.cyan, Color.orange, Color.magenta}; private String style = "line"; public MultiProfilePanel(List<Profile> p, PaintableScale sc) { profiles = p; scale = sc; for(Profile profile : profiles){ ProfilePaintable profilePainter = new ProfilePaintable(scale, profile); profilePainter.addPaintableChangedListener(this); profilePainters.add(profilePainter); } setPreferredSize(new Dimension(500, 300)); } public void updateFontSize(int size) { fontSize = size; repaint(); } public void setStyle(String s) { style = s; repaint(); } public Action createSaveImageAction() { return new AbstractAction("Save Meta-Point Image...") { /** * Comment for <code>serialVersionUID</code> */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { String pwdName = System.getProperty("user.dir"); JFileChooser chooser; if(pwdName != null) { chooser = new JFileChooser(new File(pwdName)); } else { chooser = new JFileChooser(); } int v = chooser.showSaveDialog(null); if(v == JFileChooser.APPROVE_OPTION) { File f = chooser.getSelectedFile(); try { saveImage(f, getWidth(), getHeight()); //System.out.println("Saved Image [" + sImageWidth + " by " + sImageHeight + "]"); } catch(IOException ie) { ie.printStackTrace(System.err); } } } }; } public void saveImage(File f, int w, int h) throws IOException { this.setSize(new Dimension(w, h)); repaint(); BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Graphics g = im.getGraphics(); Graphics2D g2 = (Graphics2D)g; g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); this.paint(g); ImageIO.write(im, "png", f); } protected void paintComponent(Graphics g) { int w = getWidth(), h = getHeight(); super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; g2.setColor(Color.white); g2.fillRect(0, 0, w, h); double profileMax =0, profileMin=Double.MAX_VALUE; int binPix=0, profileLength=0; BinningParameters bps = profiles.get(0).getBinningParameters(); boolean isStranded=false; FontMetrics metrics; //Params for(int p=0; p<profiles.size(); p++){ if(binPix < w / (profiles.get(p).length()+1)) binPix = w / (profiles.get(p).length()+1); if(profileLength < profiles.get(p).length()) profileLength = profiles.get(p).length(); if(profileMax < profiles.get(p).max()) profileMax = profiles.get(p).max(); if(profileMin > profiles.get(p).min()) profileMin = profiles.get(p).min(); isStranded = isStranded || profiles.get(p).isStranded(); scale.setScale(profileMin, profileMax); } //Profiles for(int p=0; p<profiles.size(); p++){ profilePainters.get(p).setColor(peakColors[p%peakColors.length]); profilePainters.get(p).setStyle(style); profilePainters.get(p).paintItem(g, border, 0, w, h-border); } g2.setFont(new Font("Arial", Font.PLAIN, fontSize)); metrics = g2.getFontMetrics(); //Legend int maxLegendWidth =0; for(int p=0; p<profiles.size(); p++){ String counter=String.format("%s: %d datapoints", profiles.get(p).getName(), profiles.get(p).getNumProfiles()); maxLegendWidth = Math.max(maxLegendWidth, metrics.stringWidth(counter)); }for(int p=0; p<profiles.size(); p++){ g2.setColor(peakColors[p%peakColors.length]); String counter=String.format("%s: %d datapoints", profiles.get(p).getName(), profiles.get(p).getNumProfiles()); g2.drawString(counter, w-border-maxLegendWidth, fontSize+(fontSize*p)); } //Paint labels & Y-axis stuff g2.setFont(new Font("Arial", Font.PLAIN, fontSize)); metrics = g2.getFontMetrics(); g2.setColor(Color.black); if(profileMax<10 && profileMax>1) g2.drawString(String.format("%.2f", scale.getMax()), border/2, fontSize); else if(profileMax>=1 || profileMax==0) g2.drawString(String.format("%.0f", scale.getMax()), border/2, fontSize); else g2.drawString(String.format("%.2e", scale.getMax()), border/2, fontSize); if(profileMin==0 || profileMin<=-1) g2.drawString(String.format("%.0f", scale.getMin()), border/2, h-border-1); else g2.drawString(String.format("%.2e", scale.getMin()), border/2, h-border-1); //X-axis int xaxispos=h-border; if(profileMin<0){ double frac =scale.getMax()/(scale.getMax()-scale.getMin()); xaxispos = (int)((double)((h-border-1))*frac); g2.drawString("0", border/2, xaxispos); } g2.setColor(Color.DARK_GRAY); g2.drawLine(border, h-border, (binPix*profileLength)+border, h-border); String minVal = String.format("%d", -1*(bps.getWindowSize()/2)); String maxVal = String.format("%d", (bps.getWindowSize()/2)); g2.drawString(maxVal, border+(binPix*profileLength)-metrics.stringWidth(maxVal), h); g2.drawString(minVal, border, h); //Draw marker line g2.setColor(Color.black); if(isStranded){ g2.setStroke(new BasicStroke((float)lineWidth)); int [] a=new int [7]; int [] b=new int [7]; arrangeArrow(a, b, lineHeight, border+(binPix*(profileLength/2)), border+(binPix*(profileLength/2))+150, h-border); g2.drawPolyline(a, b, 7); }else{ g2.fillRect(border+(binPix*(profileLength/2))-lineWidth/2, h-lineHeight-(border/2), lineWidth, lineHeight); } } public void paintableChanged(PaintableChangedEvent pce) { repaint(); } private void arrangeArrow(int[] a, int[] b, int height, int gx1, int gx2, int my) { double arrowHt =0.1 *height; double arrowWd = 2; int a1, a2, a3; int startX = gx1; a1 = startX; a2 = (int) Math.round(startX + (arrowWd * 6)); a3 = (int) Math.round(startX + (arrowWd * 10)); a[0] = a1; a[1] = a1; a[2] = a2; a[3] = a2; a[4] = a3; a[5] = a2; a[6] = a2; int b1 = (int) Math.round(my); int b2 = (int) Math.round(my - (arrowHt * 13)); int b3 = (int) Math.round(my - (arrowHt * 10)); int b4 = (int) Math.round(my - (arrowHt * 16)); b[0] = b1; b[1] = b2; b[2] = b2; b[3] = b3; b[4] = b2; b[5] = b4; b[6] = b2; } }