package org.seqcode.viz.metaprofile.swing; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.*; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import javax.swing.*; import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.svggen.SVGGraphics2D; import org.seqcode.viz.metaprofile.*; import org.seqcode.viz.paintable.PaintableScale; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; public class ProfileLinePanel extends JPanel implements ProfileListener{ private BinningParameters params; private PaintableScale scale; private int width = 500; private int lineWeight=1; private boolean lineImageRaster=true; private ProfileClusteringHandler clusteringHandler; private int numAxisTicks=5; private int fontSize=20; private Color lineColor =Color.blue; private int colorbarHeight=50; private boolean addPercentages=false; private Vector<ProfileLinePaintable> linePainters; private boolean colorQuantized=false; private double [] colorQuantaLimits=null; private boolean drawColorBar=true; private boolean drawBorder = true; private boolean transparent = false; public ProfileLinePanel(BinningParameters bps, PaintableScale s) { params = bps; scale = s; linePainters = new Vector<ProfileLinePaintable>(); clusteringHandler = new ProfileClusteringHandler(params); width = params.getNumBins(); setPreferredSize(new Dimension(width, 300)); } public void cluster() { System.out.println("Getting Profiles..."); Vector<Profile> profs = getAllProfiles(); System.out.println("Clustering..."); Vector<Integer> permutation = clusteringHandler.runClustering(profs); System.out.println("Reordering..."); reorder(permutation); System.out.println("Done."); } public synchronized Vector<Profile> getAllProfiles() { Vector<Profile> profs = new Vector<Profile>(); for(int i = 0; i < linePainters.size(); i++) { profs.add(linePainters.get(i).getProfile()); } return profs; } public synchronized void reorder(Vector<Integer> indices) { Vector<ProfileLinePaintable> newLinePainters = new Vector<ProfileLinePaintable>(); for(Integer idx : indices) { newLinePainters.add(linePainters.get(idx)); } linePainters = newLinePainters; repaint(); } public synchronized void addProfileLinePaintable(ProfileLinePaintable plp) { if(colorQuantized) plp.setQuanta(colorQuantaLimits); linePainters.add(plp); if(linePainters.size() % 10 == 0) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateSize(); } }); repaint(); } } public int getPanelWidth(){ return(width); } public int getPanelLength(){ return(colorbarHeight+(linePainters.size()*lineWeight)+lineWeight+1); } private void updateSize() { setPreferredSize(new Dimension(width, colorbarHeight+(linePainters.size()*lineWeight)+lineWeight+1)); setSize(new Dimension(width, colorbarHeight+(linePainters.size()*lineWeight)+lineWeight+1)); } public void updateFontSize(int size) { fontSize = size; repaint(); } public void updateLineWeight(int w) { lineWeight = w; updateSize(); repaint(); } public void updateColor(Color c) { lineColor=c; repaint(); } public double getMaxColorVal(){return scale.getMax();} public void setMaxColorVal(double v){ scale.setScale(scale.getMin(), v); repaint(); } public double getMinColorVal(){return scale.getMin();} public void setMinColorVal(double v){ scale.setScale(v, scale.getMax()); repaint(); } public void setDrawColorBar(boolean c){ drawColorBar = c; if(!c) colorbarHeight=0; else colorbarHeight=50; } public void setTransparent(boolean c){ transparent = c; } public void setLineColorQuanta(double[] q){ if(q!=null){ colorQuantaLimits=q; colorQuantized=true; } } protected void paintComponent(Graphics g) { super.paintComponent(g); int w = getWidth(), h = getHeight(); if(!transparent){ g.setColor(Color.white); g.fillRect(0, 0, w, h); } //Colorbar if(drawColorBar) drawSiteColorBar((Graphics2D)g, 0, 0); //Lines synchronized(this) { for(int i = 0; i < linePainters.size(); i++) { linePainters.get(i).setColor(lineColor); linePainters.get(i).paintItem(g, 0, colorbarHeight+i*lineWeight, w, colorbarHeight+(i*lineWeight)+lineWeight+1); } } //Labels, axes, etc g.setColor(Color.DARK_GRAY); if(linePainters.size()>0){ g.drawLine(0, colorbarHeight-1, w, colorbarHeight-1); int lastLine = colorbarHeight+(linePainters.size()*lineWeight)+lineWeight+1; g.drawLine(0, lastLine, w, lastLine); } //Axis g.setFont(new Font("Arial", Font.PLAIN, fontSize)); FontMetrics metrics = g.getFontMetrics(); g.setColor(Color.black); if(addPercentages){ if(linePainters.size()>(numAxisTicks*10)){ for(int i=1; i<=numAxisTicks; i++){ int l = (100/numAxisTicks)*i; String s = String.format("%d%c", l, '%'); g.drawString(s, w-5-metrics.stringWidth(s), colorbarHeight+(i*((linePainters.size()*lineWeight)/numAxisTicks))); } } } //Border if(drawBorder){ g.setColor(Color.black); g.drawRect(0, 0, w, h); } } public void profileChanged(ProfileEvent p) { if(p.getType().equals(ProfileEvent.EventType.ADDED)) { Profile added = p.addedProfile(); ProfileLinePaintable plp = new ProfileLinePaintable(scale, added); scale.updateScale(added.max()); scale.updateScale(added.min()); addProfileLinePaintable(plp); } } public Action createSaveImageAction() { return new AbstractAction("Save Profile 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(), colorbarHeight+(linePainters.size()*lineWeight)+lineWeight+1, true); //System.out.println("Saved Image [" + sImageWidth + " by " + sImageHeight + "]"); } catch(IOException ie) { ie.printStackTrace(System.err); } } } }; } public void saveImage(File f, int w, int h, boolean raster) throws IOException { if(raster){ if(transparent) this.setOpaque(false); BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = im.createGraphics(); graphics.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); this.print(graphics); graphics.dispose(); ImageIO.write(im, "png", f); }else{ DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); // Create an instance of org.w3c.dom.Document Document document = domImpl.createDocument(null, "svg", null); // Create an instance of the SVG Generator SVGGraphics2D svgGenerator = new SVGGraphics2D(document); svgGenerator.setSVGCanvasSize(new Dimension(w,h)); // Ask the test to render into the SVG Graphics2D implementation if(!transparent){ svgGenerator.setColor(Color.white); svgGenerator.fillRect(0,0,w,h); } this.paintComponent(svgGenerator); // Finally, stream out SVG to the standard output using UTF-8 // character to byte encoding boolean useCSS = true; // we want to use CSS style attribute FileOutputStream outStream = new FileOutputStream(f); Writer out = new OutputStreamWriter(outStream, "UTF-8"); svgGenerator.stream(out, useCSS); outStream.flush(); outStream.close(); } } private void drawSiteColorBar(Graphics2D g2d, int x, int y){ int cWidth = getWidth(); int cHeight = colorbarHeight-5; //Draw colors if(!colorQuantized){ GradientPaint colorbar = new GradientPaint(x, y, Color.white, x+cWidth, y, lineColor, false); g2d.setPaint(colorbar); g2d.fillRect(x, y, cWidth, cHeight); }else{ for(int i=0; i<colorQuantaLimits.length; i++){ int off =(int)x+(i*(int)(cWidth/(double)colorQuantaLimits.length)); g2d.setColor(calcFracColor(lineColor, (double)i/(double)(colorQuantaLimits.length-1))); g2d.fillRect(off, y, (int)(cWidth/(double)colorQuantaLimits.length), cHeight); } } g2d.setPaint(Color.black); g2d.setColor(Color.black); //Zero tick if needed if(scale.getMin()<0){ int zeroOff = (int)((double)cWidth*(0-scale.getMin())/(scale.getMax()-scale.getMin())); g2d.setStroke(new BasicStroke(1.0f)); g2d.drawLine(zeroOff, 0,zeroOff, cHeight); } //Draw border g2d.setStroke(new BasicStroke(1.0f)); g2d.drawRect(x, y, cWidth, cHeight); //Legend g2d.setColor(Color.white); g2d.setFont(new Font("Ariel", Font.BOLD, 20)); FontMetrics metrics = g2d.getFontMetrics(); String maxVal; if(scale.getMax()>=1 || scale.getMax()==0) maxVal = String.format("%.0f",scale.getMax()); else maxVal = String.format("%.2e",scale.getMax()); g2d.drawString(maxVal, x+cWidth-(metrics.stringWidth(maxVal)), cHeight-2); } private Color calcFracColor(Color col, double v){ Color c; Color maxColor = col; Color minColor = Color.white; double sVal = v>1 ? 1 : (v<0 ? 0 : v); int red = (int)(maxColor.getRed() * sVal + minColor.getRed() * (1 - sVal)); int green = (int)(maxColor.getGreen() * sVal + minColor.getGreen() * (1 - sVal)); int blue = (int)(maxColor.getBlue() *sVal + minColor.getBlue() * (1 - sVal)); c = new Color(red, green, blue); return(c); } }