/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.tools.xgmml;
import static java.lang.String.format;
import static org.openbel.framework.common.BELUtilities.hasLength;
import java.io.PrintWriter;
import java.util.List;
import java.util.Random;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelTerm;
import org.openbel.framework.common.enums.FunctionEnum;
import org.openbel.framework.common.enums.RelationshipType;
import org.openbel.framework.tools.xgmml.XGMMLObjects.Edge;
import org.openbel.framework.tools.xgmml.XGMMLObjects.Node;
/**
* XGMMLUtility provides utility methods for writing graph, node, and edge
* sections of an XGMML xml document.
*
* @author Anthony Bargnesi {@code <abargnesi@selventa.com>}
*/
public class XGMMLUtility {
/**
* Format: {@code %s %s %d %d}. In order, graphics type, fill color, x-pos,
* and y-pos.
*/
private static String NODE_GRAPHICS;
/**
* Format: {@code %d %s %d %s}. In order, line width, fill color, target
* arrow indicator, and edge label.
*/
private static String EDGE_GRAPHICS;
/**
* Format: {@code %s %s %s}.
*/
private static String EDGE_LABEL;
private static String DFLT_NODE_SHAPE;
private static String DFLT_EDGE_COLOR;
private static String DFLT_NODE_COLOR;
static {
NODE_GRAPHICS = " <graphics type='%s' fill='%s' ";
NODE_GRAPHICS += "x='%d' y='%d' h='20.0' w='80.0' ";
NODE_GRAPHICS += "cy:nodeLabel='%s'/>\n";
EDGE_GRAPHICS = " <graphics width='%d' fill='%s' ";
EDGE_GRAPHICS += "cy:targetArrow='%d' cy:edgeLabel='%s'/>\n";
EDGE_LABEL = "%s (%s) %s";
DFLT_NODE_SHAPE = "rectangle";
DFLT_EDGE_COLOR = "0,0,0";
DFLT_NODE_COLOR = "150,150,150";
}
/**
* Returns a shape for the supplied {@link FunctionEnum}.
*
* @param fe {@link FunctionEnum}
* @return Non-null {@link String}
* @see #DFLT_NODE_SHAPE
*/
public static String type(FunctionEnum fe) {
if (fe == null) {
return DFLT_NODE_SHAPE;
}
switch (fe) {
case ABUNDANCE:
return "ver_ellipsis";
case BIOLOGICAL_PROCESS:
return "rhombus";
case CATALYTIC_ACTIVITY:
return "hexagon";
case CELL_SECRETION:
return "arc";
case CELL_SURFACE_EXPRESSION:
return "arc";
case CHAPERONE_ACTIVITY:
return "hexagon";
case COMPLEX_ABUNDANCE:
return "hor_ellipsis";
case COMPOSITE_ABUNDANCE:
return "hor_ellipsis";
case DEGRADATION:
return "hor_ellipsis";
case GENE_ABUNDANCE:
return "hor_ellipsis";
case GTP_BOUND_ACTIVITY:
return "hexagon";
case KINASE_ACTIVITY:
return "hexagon";
case MICRORNA_ABUNDANCE:
return "hor_ellipsis";
case MOLECULAR_ACTIVITY:
return "hexagon";
case PATHOLOGY:
return "rhombus";
case PEPTIDASE_ACTIVITY:
return "hexagon";
case PHOSPHATASE_ACTIVITY:
return "hexagon";
case PRODUCTS:
case PROTEIN_ABUNDANCE:
return "hor_ellipsis";
case REACTANTS:
case RIBOSYLATION_ACTIVITY:
return "hexagon";
case RNA_ABUNDANCE:
return "hor_ellipsis";
case TRANSCRIPTIONAL_ACTIVITY:
return "hexagon";
case TRANSPORT_ACTIVITY:
return "hexagon";
}
return DFLT_NODE_SHAPE;
}
/**
* Returns an RGB tuple of the form {@code "x,x,x"} for the supplied
* {@link FunctionEnum}. Defaults to gray; RGB {@code "150,150,150"}.
*
* @param fe {@link FunctionEnum}
* @return Non-null {@link String}
*/
public static String color(FunctionEnum fe) {
if (fe == null) {
return DFLT_NODE_COLOR;
}
switch (fe) {
case ABUNDANCE:
return "40,255,85";
case BIOLOGICAL_PROCESS:
return "255,51,102";
case CATALYTIC_ACTIVITY:
return "100,100,255";
case CELL_SECRETION:
return "204,204,255";
case CELL_SURFACE_EXPRESSION:
return "204,204,255";
case CHAPERONE_ACTIVITY:
return "100,100,255";
case COMPLEX_ABUNDANCE:
return "102,153,255";
case COMPOSITE_ABUNDANCE:
return "222,255,255";
case DEGRADATION:
return "255,51,102";
case GENE_ABUNDANCE:
return "204,255,204";
case GTP_BOUND_ACTIVITY:
return "100,100,255";
case KINASE_ACTIVITY:
return "100,100,255";
case MICRORNA_ABUNDANCE:
return "0,255,150";
case MOLECULAR_ACTIVITY:
return "100,100,255";
case PATHOLOGY:
return "255,51,102";
case PEPTIDASE_ACTIVITY:
return "100,100,255";
case PHOSPHATASE_ACTIVITY:
return "100,100,255";
case PROTEIN_ABUNDANCE:
return "85,255,255";
case REACTION:
return "255,51,102";
case RIBOSYLATION_ACTIVITY:
return "100,100,255";
case RNA_ABUNDANCE:
return "40,255,85";
case TRANSCRIPTIONAL_ACTIVITY:
return "100,100,255";
case TRANSPORT_ACTIVITY:
return "100,100,255";
}
return DFLT_NODE_COLOR;
}
/**
* Returns an RGB tuple of the form {@code "x,x,x"} for the supplied
* {@link RelationshipType}. Defaults to black; RGB {@code "0,0,0"}.
*
* @param fe {@link RelationshipType}
* @return Non-null {@link String}
*/
public static String color(RelationshipType rel) {
if (rel == null) {
return DFLT_EDGE_COLOR;
}
switch (rel) {
case ACTS_IN:
return "153,153,153";
case HAS_COMPONENT:
return "153,153,153";
case HAS_MEMBER:
return "153,153,153";
case HAS_MODIFICATION:
return "153,153,153";
case HAS_PRODUCT:
return "153,153,153";
case HAS_VARIANT:
return "153,153,153";
case INCLUDES:
return "153,153,153";
case IS_A:
return "153,153,153";
case REACTANT_IN:
return "153,153,153";
case SUB_PROCESS_OF:
return "153,153,153";
case TRANSCRIBED_TO:
return "153,153,153";
case TRANSLATED_TO:
return "153,153,153";
case TRANSLOCATES:
return "153,153,153";
}
return DFLT_EDGE_COLOR;
}
/**
* Write the XGMML start using the {@code graphName} as the label.
*
* @param name {@link String}, the name of the XGMML graph
* @param writer {@link PrintWriter}, the writer
*/
public static void writeStart(String name, PrintWriter writer) {
StringBuilder sb = new StringBuilder();
sb.append("<graph xmlns='http://www.cs.rpi.edu/XGMML' ")
.append("xmlns:ns2='http://www.w3.org/1999/xlink' ")
.append("xmlns:cy='http://www.cytoscape.org' ")
.append("Graphic='1' label='").append(name)
.append("' directed='1'>\n");
writer.write(sb.toString());
}
/**
* Write an XGMML {@code <node>} from {@code node} properties.
*
* @param node {@link Node}, the node to write
* @param writer {@link PrintWriter}, the writer
*/
public static void writeNode(Node node, List<BelTerm> supportingTerms,
PrintWriter writer) {
int x = new Random().nextInt(200);
int y = new Random().nextInt(200);
StringBuilder sb = new StringBuilder();
sb.append(" <node label='");
sb.append(node.label);
sb.append("' id='");
sb.append(node.id.toString());
sb.append("'>\n");
sb.append(" <att name='function type'");
sb.append(" value='");
sb.append(node.function.getDisplayValue());
sb.append("' />\n");
sb.append(" <att name='parameters'");
sb.append(" value='");
String params = "";
for (BelTerm t : supportingTerms) {
if (hasLength(params)) {
params = params.concat("
");
}
String label = t.getLabel();
label = label.replaceAll("&", "&");
label = label.replaceAll("'", """);
params = params.concat(label);
}
sb.append(params);
sb.append("' />\n");
// Graphics type and fill color
String graphics = format(NODE_GRAPHICS, type(node.function),
color(node.function), x, y, params);
sb.append(graphics);
sb.append(" </node>\n");
writer.write(sb.toString());
}
/**
* Write an XGMML <edge> from {@code edge} properties.
*
* @param edge {@link Edge}, the edge to write
* @param writer {@link PrintWriter}, the writer
*/
public static void writeEdge(Node src, Node tgt, Edge edge,
PrintWriter writer) {
StringBuilder sb = new StringBuilder();
RelationshipType rel = edge.rel;
String reldispval = rel.getDisplayValue();
sb.append(" <edge label='");
String dispval = format(EDGE_LABEL, src.label, rel, tgt.label);
sb.append(dispval);
sb.append("' source='");
sb.append(edge.source.toString());
sb.append("' target='");
sb.append(edge.target.toString());
sb.append("'>\n");
sb.append(" <att name='relationship type'");
sb.append(" value='");
sb.append(reldispval);
sb.append("' />\n");
// Edge graphics
String color = color(rel);
String graphics = format(EDGE_GRAPHICS, 1, color, 1, reldispval);
sb.append(graphics);
sb.append(" </edge>\n");
writer.write(sb.toString());
}
/**
* Write the XGMML end.
*
* @param writer {@link PrintWriter}, the writer
*/
public static void writeEnd(PrintWriter writer) {
writer.write("</graph>");
}
}