public static void main(String[] args) throws Exception { // Create an SVG document. DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null); // Create a converter for this document. SVGGraphics2D g = new SVGGraphics2D(doc); // Do some drawing. Shape circle = new Ellipse2D.Double(0, 0, 50, 50); g.setPaint(Color.red); g.fill(circle); g.translate(60, 0); g.setPaint(Color.green); g.fill(circle); g.translate(60, 0); g.setPaint(Color.blue); g.fill(circle); g.setSVGCanvasSize(new Dimension(180, 50)); // Populate the document root with the generated SVG content. Element root = doc.getDocumentElement(); g.getRoot(root); Writer out = new OutputStreamWriter(System.out, "UTF-8"); g.stream(out, true); // Display the document. JSVGCanvas canvas = new JSVGCanvas(); JFrame f = new JFrame(); f.getContentPane().add(canvas); canvas.setSVGDocument(doc); f.pack(); f.setVisible(true); }
/** * Draws a complex graph * * @param nonProteinGraph whether the graph is a non-protein graph and should be drawn black and * white * @param cg the complex graph * @param molInfoForChains info mapping chain IDs (like "A") to their macromolecule (MOL_ID in PDB * file, e.g., "1"). Give an empty one if you dont know * @return a draw result */ private static DrawResult drawChainLevelComplexGraphG2D( Boolean nonProteinGraph, ComplexGraph cg, Map<String, String> molInfoForChains) { Integer numVerts = cg.getVertices().size(); Boolean bw = nonProteinGraph; // All these values are in pixels // page setup PageLayout pl = new PageLayout(numVerts); Position2D vertStart = pl.getVertStart(); // ------------------------- Prepare stuff ------------------------- // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed into integer pixels // BufferedImage bi = new BufferedImage(pl.getPageWidth(), pl.getPageHeight(), // BufferedImage.TYPE_INT_ARGB); SVGGraphics2D ig2; // if(Settings.get("plcc_S_img_output_format").equals("SVG")) { // Apache Batik SVG library, using W3C DOM tree implementation // Get a DOMImplementation. DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); // Create an instance of org.w3c.dom.Document. String svgNS = "http://www.w3.org/2000/svg"; Document document = domImpl.createDocument(svgNS, "svg", null); // Create an instance of the SVG Generator. ig2 = new SVGGraphics2D(document); // ig2.getRoot(document.getDocumentElement()); // } // else { // ig2 = (SVGGraphics2D)bi.createGraphics(); // } ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // make background white ig2.setPaint(Color.WHITE); ig2.fillRect(0, 0, pl.getPageWidth(), pl.getPageHeight()); ig2.setPaint(Color.BLACK); // pl.drawAreaOutlines(ig2); // prepare font Font font = pl.getStandardFont(); ig2.setFont(font); FontMetrics fontMetrics = ig2.getFontMetrics(); // ------------------------- Draw header ------------------------- // check width of header string String proteinHeader = "The chain complex graph of PDB entry " + cg.pdbid + " [V=" + cg.getVertices().size() + ", E=" + cg.getEdges().size() + "]."; String addInfo = "(Interchain contact threshold is set to " + Main.chainComplexGraphContactThreshold + ". Neglected edges: " + cg.neglectedEdges + ")"; // Integer stringWidth = fontMetrics.stringWidth(proteinHeader); // Should be around 300px // for the text above Integer stringHeight = fontMetrics.getAscent(); String chainName; // the SSE number in the primary structure, N to C terminus String chainNumber; // the SSE number in this graph, 1..(this.size) if (Settings.getBoolean("plcc_B_graphimg_header")) { ig2.drawString(proteinHeader, pl.headerStart.x, pl.headerStart.y); // i2.drawString(addInfo, pl.headerStart.x, pl.headerStart.y + pl.textLineHeight); } // ------------------------- Draw the graph ------------------------- // Draw the edges as arcs java.awt.Shape shape; Arc2D.Double arc; ig2.setStroke(new BasicStroke(2)); // thin edges Integer edgeType, leftVert, rightVert, leftVertPosX, rightVertPosX, arcWidth, arcHeight, arcTopLeftX, arcTopLeftY, spacerX, spacerY, iChainID, jChainID; Integer labelPosX, labelPosY; String edges = cg.getEdges().toString(); for (Integer i = 0; i < cg.getVertices().size(); i++) { for (Integer j = i + 1; j < cg.getVertices().size(); j++) { String tmp = "(" + i + ", " + j + ")"; // If there is a contact... if (edges.indexOf(tmp) != -1) { Integer cInteractions = cg.numChainInteractions[i][j]; // determine edge type and the resulting color // edgeType = cg.getContactType(i, j); ig2.setPaint(Color.RED); if (bw) { ig2.setPaint(Color.LIGHT_GRAY); } // for non-protein graphs // ----- complex graph specific stuff ----- // determine chain of SSEs iChainID = -1; jChainID = -1; /* for(Integer x = 0; x < cg.chainEnd.size(); x++){ if(i < cg.chainEnd.get(x)) {iChainID = x; break;} } for(Integer x = 0; x < cg.chainEnd.size(); x++){ if(j < cg.chainEnd.get(x)) {jChainID = x; break;} } if (!Objects.equals(iChainID, jChainID)) {ig2.setPaint(Color.PINK);} */ // ----- end complex graph specific stuff ----- // determine the center of the arc and the width of its rectangle bounding box if (i < j) { leftVert = i; rightVert = j; } else { leftVert = j; rightVert = i; } leftVertPosX = pl.getVertStart().x + (leftVert * pl.vertDist); rightVertPosX = pl.getVertStart().x + (rightVert * pl.vertDist); arcWidth = rightVertPosX - leftVertPosX; arcHeight = arcWidth / 2; arcTopLeftX = leftVertPosX; arcTopLeftY = pl.getVertStart().y - arcHeight / 2; spacerX = pl.vertRadius; spacerY = 0; // draw it arc = new Arc2D.Double( arcTopLeftX + spacerX, arcTopLeftY + spacerY, arcWidth, arcHeight, 0, 180, Arc2D.OPEN); shape = ig2.getStroke().createStrokedShape(arc); ig2.fill(shape); } } } // draw arc labels on top to prevent unreadability for (Integer i = 0; i < cg.getVertices().size(); i++) { for (Integer j = i + 1; j < cg.getVertices().size(); j++) { String tmp = "(" + i + ", " + j + ")"; // If there is a contact... if (edges.indexOf(tmp) != -1) { iChainID = -1; jChainID = -1; if (i < j) { leftVert = i; rightVert = j; } else { leftVert = j; rightVert = i; } // TODO: is it clever to calculate everything again? leftVertPosX = pl.getVertStart().x + (leftVert * pl.vertDist); rightVertPosX = pl.getVertStart().x + (rightVert * pl.vertDist); arcWidth = rightVertPosX - leftVertPosX; arcHeight = arcWidth / 2; arcTopLeftX = leftVertPosX; arcTopLeftY = pl.getVertStart().y - arcHeight / 2; spacerX = pl.vertRadius; spacerY = 0; // calculate label positions labelPosX = leftVertPosX + arcWidth / 2 + 2; labelPosY = arcTopLeftY + spacerY - 5; // draw labels on arcs Font labelfont = new Font( Settings.get("plcc_S_img_default_font"), Font.PLAIN, Settings.getInteger("plcc_I_img_default_font_size") - 5); ig2.setFont(labelfont); ig2.setPaint(Color.BLACK); Integer cInteractions = cg.numChainInteractions[i][j]; if (cInteractions != null) { ig2.drawString(cInteractions.toString(), labelPosX, labelPosY + (stringHeight / 4)); } } } } ig2.setFont(font); // Draw the vertices as circles Ellipse2D.Double circle; Rectangle2D.Double rect; ig2.setStroke(new BasicStroke(2)); boolean colorSet = false; cg.savedVertexColors = new float[cg.getVertices().size()]; for (Integer i = 0; i < cg.getVertices().size(); i++) { // set standard color ig2.setPaint(Color.GRAY); if (bw) { ig2.setPaint(Color.GRAY); } // for non-protein graphs // set hue, saturation, brighness float h = (float) 0.5; float s = (float) 1.0; // change this for saturation (higher = more saturated) float b = (float) 0.8; // change this for brightness (0.0 -> Dark/Black) for (Integer j = 0; j < cg.getVertices().size(); j++) { // if chain has an homologue partner... if (cg.homologueChains[i][j] != null) { if (cg.homologueChains[i][j] == 1) { // if homologue partner wasn't colored before.. if (cg.savedVertexColors[i] == 0) { h = cg.getUniqueColor(numVerts); // get unique color for (int y = j; y < cg.homologueChains.length; y++) { if (cg.homologueChains[i][y] == 1) { cg.savedVertexColors[i] = h; cg.savedVertexColors[y] = h; } } colorSet = true; } else { h = cg.savedVertexColors[i]; } ig2.setPaint(Color.getHSBColor(h, s, b)); colorSet = true; } } } // if no homologue chains occur if (!colorSet) { h = cg.getUniqueColor(numVerts); // get unique color cg.savedVertexColors[i] = h; ig2.setPaint(Color.getHSBColor(h, s, b)); } colorSet = false; // pick color depending on SSE type // draw a shape based on SSE type rect = new Rectangle2D.Double( vertStart.x + (i * pl.vertDist), vertStart.y, pl.getVertDiameter(), pl.getVertDiameter()); ig2.fill(rect); } // Draw the markers for the N-terminus and C-terminus if there are any vertices in this graph ig2.setStroke(new BasicStroke(2)); ig2.setPaint(Color.BLACK); /* if( ! bw) { if(cg.getVertices().size() > 0) { ig2.drawString("N", vertStart.x - pl.vertDist, vertStart.y + 20); // N terminus label ig2.drawString("C", vertStart.x + cg.getVertices().size() * pl.vertDist, vertStart.y + 20); // C terminus label } } */ // ************************************* footer ************************************** if (Settings.getBoolean("plcc_B_graphimg_footer")) { // Draw the vertex numbering into the footer // Determine the dist between vertices that will have their vertex number printed below them // in the footer field Integer printNth = 1; if (cg.getVertices().size() > 9) { printNth = 1; } if (cg.getVertices().size() > 99) { printNth = 2; } // line markers: S for sequence order, G for graph order Integer lineHeight = pl.textLineHeight; if (cg.getVertices().size() > 0) { ig2.drawString( "C#", pl.getFooterStart().x - pl.vertDist, pl.getFooterStart().y + (stringHeight / 4)); ig2.drawString( "CN", pl.getFooterStart().x - pl.vertDist, pl.getFooterStart().y + lineHeight + (stringHeight / 4)); ig2.drawString( "ML", pl.getFooterStart().x - pl.vertDist, pl.getFooterStart().y + (lineHeight * 2) + (stringHeight / 4)); } else { ig2.drawString("(Graph has no vertices.)", pl.getFooterStart().x, pl.getFooterStart().y); } iChainID = -1; String edgesString = cg.proteinNodeMap.toString(); // System.out.println("DrawChainLevelCG: edgesString is '" + edgesString + "'."); for (Integer i = 0; i < cg.getVertices().size(); i++) { // Draw label for every nth vertex if ((i + 1) % printNth == 0) { chainNumber = "" + (i + 1); // sseNumberSeq = "" + (cg.proteinNodeMap.get(i)); Integer foundIndex = edgesString.indexOf(i.toString() + "="); String chainId; if (i < 10) { chainId = edgesString.substring(foundIndex + 2, foundIndex + 3); } else { chainId = edgesString.substring(foundIndex + 3, foundIndex + 4); } chainName = "" + chainId; // stringWidth = fontMetrics.stringWidth(sseNumberSeq); stringHeight = fontMetrics.getAscent(); ig2.drawString( chainNumber, pl.getFooterStart().x + (i * pl.vertDist) + pl.vertRadius / 2, pl.getFooterStart().y + (stringHeight / 4)); ig2.drawString( chainName, pl.getFooterStart().x + (i * pl.vertDist) + pl.vertRadius / 2, pl.getFooterStart().y + (lineHeight * 1) + (stringHeight / 4)); ig2.drawString( molInfoForChains.get(chainName), pl.getFooterStart().x + (i * pl.vertDist) + pl.vertRadius / 2, pl.getFooterStart().y + (lineHeight * 2) + (stringHeight / 4)); // determine chain of SSEs /*for(Integer x = 0; x < cg.getVertices().size(); x++){ if(i < cg.chainEnd.get(x)) {iChainID = x; break;} } */ // if(iChainID != -1) {ig2.drawString(cg.allChains.get(iChainID).getPdbChainID(), // pl.getFooterStart().x + (i * pl.vertDist) + pl.vertRadius / 2, pl.getFooterStart().y + // (lineHeight * 2) + (stringHeight / 4));} } } /* if(Settings.getBoolean("plcc_B_graphimg_legend")) { if(iChainID != -1){ SSEGraph.drawLegend(ig2, new Position2D(pl.getFooterStart().x, pl.getFooterStart().y + lineHeight * 3 + (stringHeight / 4)), pl, pg); } else{ SSEGraph.drawLegend(ig2, new Position2D(pl.getFooterStart().x, pl.getFooterStart().y + lineHeight * 2 + (stringHeight / 4)), pl, pg); } } */ } // all done, write the image to disk // if(Settings.get("plcc_S_img_output_format").equals("SVG")) { // boolean useCSS = true; // FileOutputStream fos = new FileOutputStream(new File("/tmp/mySVG.svg")); // Writer out = new OutputStreamWriter(fos, "UTF-8"); // ig2.stream(out, useCSS); Rectangle2D roi = new Rectangle2D.Double(0, 0, pl.getPageWidth(), pl.getPageHeight()); DrawResult drawRes = new DrawResult(ig2, roi); return drawRes; }